diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d1baef057..8a60b54062 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,18 @@ elseif("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") -Wfloat-conversion ${CMAKE_C_FLAGS}") endif() +# Tell Intel compiler to do arithmetic accurately. This is needed to +# stop the compiler from ignoring parentheses in expressions like +# (a + b) + c and from simplifying 0.0 + x to x (which is wrong if +# x = -0.0). +if (CMAKE_C_COMPILER_ID STREQUAL "Intel") + if (MSVC) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fp:precise") + else () + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprotect-parens -fsigned-zeros") + endif () +endif () + ################################################################################# # PROJ4 CMake modules ################################################################################# diff --git a/configure.ac b/configure.ac index 898d8b3bab..ee5fc5073d 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,12 @@ CFLAGS="$save_CFLAGS" dnl We check for headers AC_HEADER_STDC +dnl Check flag for accurate arithmetic with Intel compiler. This is +dnl needed to stop the compiler from ignoring parentheses in expressions +dnl like (a + b) + c and from simplifying 0.0 + x to x (which is wrong if +dnl x = -0.0). +AX_CHECK_COMPILE_FLAG([-fprotect-parens -fsigned-zeros], + [CFLAGS="$CFLAGS -fprotect-parens -fsigned-zeros"],,[-Werror]) dnl Check for C99 math functions save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Wall -Werror" diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000000..dcabb92a14 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/src/geodesic.c b/src/geodesic.c index 40dffbc1b8..91af23f9f7 100644 --- a/src/geodesic.c +++ b/src/geodesic.c @@ -193,12 +193,12 @@ static real AngNormalize(real x) { real y = fmod(x, (real)(360)); #if defined(_MSC_VER) && _MSC_VER < 1900 /* - Before version 14 (2015), Visual Studio had problems dealing - with -0.0. Specifically - VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0 - sincosdx has a similar fix. - python 2.7 on Windows 32-bit machines has the same problem. - */ + * Before version 14 (2015), Visual Studio had problems dealing + * with -0.0. Specifically + * VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0 + * sincosdx has a similar fix. + * python 2.7 on Windows 32-bit machines has the same problem. + */ if (x == 0) y = x; #endif return y <= -180 ? y + 360 : (y <= 180 ? y : y - 360); @@ -239,7 +239,8 @@ static void sincosdx(real x, real* sinx, real* cosx) { r = remquo(x, (real)(90), &q); #else r = fmod(x, (real)(360)); - q = (int)(floor(r / 90 + (real)(0.5))); + /* check for NaN */ + q = r == r ? (int)(floor(r / 90 + (real)(0.5))) : 0; r -= 90 * q; #endif /* now abs(r) <= 45 */ @@ -248,13 +249,13 @@ static void sincosdx(real x, real* sinx, real* cosx) { s = sin(r); c = cos(r); #if defined(_MSC_VER) && _MSC_VER < 1900 /* - Before version 14 (2015), Visual Studio had problems dealing - with -0.0. Specifically - VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0 - VC 12 and 64-bit compile: sin(-0.0) -> +0.0 - AngNormalize has a similar fix. - python 2.7 on Windows 32-bit machines has the same problem. - */ + * Before version 14 (2015), Visual Studio had problems dealing + * with -0.0. Specifically + * VC 10,11,12 and 32-bit compile: fmod(-0.0, 360.0) -> +0.0 + * VC 12 and 64-bit compile: sin(-0.0) -> +0.0 + * AngNormalize has a similar fix. + * python 2.7 on Windows 32-bit machines has the same problem. + */ if (x == 0) s = x; #endif switch ((unsigned)q & 3U) { @@ -658,6 +659,14 @@ real geod_genposition(const struct geod_geodesicline* l, S12 = l->c2 * atan2(salp12, calp12) + l->A4 * (B42 - l->B41); } + /* In the pattern + * + * if ((outmask & GEOD_XX) && pYY) + * *pYY = YY; + * + * the second check "&& pYY" is redundant. It's there to make the CLang + * static analyzer happy. + */ if ((outmask & GEOD_LATITUDE) && plat2) *plat2 = lat2; if ((outmask & GEOD_LONGITUDE) && plon2) @@ -1127,7 +1136,7 @@ real SinCosSeries(boolx sinp, real sinx, real cosx, const real c[], int n) { real ar, y0, y1; c += (n + sinp); /* Point to one beyond last element */ ar = 2 * (cosx - sinx) * (cosx + sinx); /* 2 * cos(2 * x) */ - y0 = (n & 1) ? *--c : 0; y1 = 0; /* accumulators for sum */ + y0 = (n & 1) ? *--c : 0; y1 = 0; /* accumulators for sum */ /* Now n is even */ n /= 2; while (n--) { @@ -1894,7 +1903,9 @@ void geod_polygon_addedge(const struct geod_geodesic* g, struct geod_polygon* p, real azi, real s) { if (p->num) { /* Do nothing is num is zero */ - real lat = 0, lon = 0, S12 = 0; /* Initialize S12 to stop Visual Studio warning */ + /* Initialize S12 to stop Visual Studio warning. Initialization of lat and + * lon is to make CLang static analyzer happy. */ + real lat = 0, lon = 0, S12 = 0; geod_gendirect(g, p->lat, p->lon, azi, GEOD_LONG_UNROLL, s, &lat, &lon, 0, 0, 0, 0, 0, p->polyline ? 0 : &S12); @@ -2031,6 +2042,8 @@ unsigned geod_polygon_testedge(const struct geod_geodesic* g, tempsum = p->A[0]; crossings = p->crossings; { + /* Initialization of lat, lon, and S12 is to make CLang static analyzer + happy. */ real lat = 0, lon = 0, s12, S12 = 0; geod_gendirect(g, p->lat, p->lon, azi, GEOD_LONG_UNROLL, s, &lat, &lon, 0, diff --git a/src/geodesic.h b/src/geodesic.h index cd7c2b7040..f9d612f3f9 100644 --- a/src/geodesic.h +++ b/src/geodesic.h @@ -132,7 +132,7 @@ * The patch level of the geodesic library. (This tracks the version of * GeographicLib.) **********************************************************************/ -#define GEODESIC_VERSION_PATCH 2 +#define GEODESIC_VERSION_PATCH 3 /** * Pack the version components into a single integer. Users should not rely on diff --git a/src/geodtest.c b/src/geodtest.c index 8cc481349a..1025ce08e9 100644 --- a/src/geodtest.c +++ b/src/geodtest.c @@ -616,7 +616,8 @@ static int GeodSolve73() { &lat2, &lon2, &azi2); result += assertEquals(lat2, 81.04623, 0.5e-5); result += assertEquals(lon2, -170, 0.5e-5); - result += assertEquals(azi2, 0, 0.5e-5); + result += azi2 == 0 ? 0 : 1; + result += 1/azi2 > 0 ? 0 : 1; /* Check that azi2 = +0.0 not -0.0 */ return result; }