build: fix fpclassify -Wfloat-conversion warning #15570

Work around a glibc bug where it truncates the argument to fpclassify()
from double to float by implementing fpclassify() ourselves.

Correctness test (Note that the FP_SUBNORMAL test depends on an atof() that
knows how to parse subnormals. Glibc does, not sure about other libcs.):

    #include <math.h>
    #include <stdint.h>
    #include <string.h>

    int xfpclassify(double d)
    {
      uint64_t m;
      int e;

      memcpy(&m, &d, sizeof(m));
      e = 0x7ff & (m >> 52);
      m = 0xfffffffffffffULL & m;

      switch (e) {
        default: return FP_NORMAL;
        case 0x000: return m ? FP_SUBNORMAL : FP_ZERO;
        case 0x7ff: return m ? FP_NAN : FP_INFINITE;
      }
    }

    #include <assert.h>
    #include <stdlib.h>

    int main(void)
    {
      assert(FP_ZERO == xfpclassify(atof("0.0")));
      assert(FP_ZERO == xfpclassify(atof("-0.0")));
      assert(FP_NORMAL == xfpclassify(atof("1.0")));
      assert(FP_NORMAL == xfpclassify(atof("-1.0")));
      assert(FP_INFINITE == xfpclassify(atof("inf")));
      assert(FP_INFINITE == xfpclassify(atof("-inf")));
      assert(FP_NAN == xfpclassify(atof("nan")));
      assert(FP_NAN == xfpclassify(atof("-nan")));
      assert(FP_SUBNORMAL == xfpclassify(atof("1.8011670033376514e-308")));
      return 0;
    }
This commit is contained in:
Ben Noordhuis
2021-09-05 16:37:25 +02:00
committed by GitHub
parent dce50312e1
commit c9c9422af0

View File

@@ -2,6 +2,8 @@
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <math.h>
#include <stdint.h>
#include <string.h>
#include "nvim/math.h"
@@ -9,34 +11,26 @@
# include "math.c.generated.h"
#endif
#if defined(__clang__) && __clang__ == 1 && __clang_major__ >= 6
// Workaround glibc + Clang 6+ bug. #8274
// https://bugzilla.redhat.com/show_bug.cgi?id=1472437
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wconversion"
#endif
int xfpclassify(double d)
{
#if defined(__MINGW32__)
// Workaround mingw warning. #7863
return __fpclassify(d);
#else
return fpclassify(d);
#endif
uint64_t m;
int e;
memcpy(&m, &d, sizeof(m));
e = 0x7ff & (m >> 52);
m = 0xfffffffffffffULL & m;
switch (e) {
default: return FP_NORMAL;
case 0x000: return m ? FP_SUBNORMAL : FP_ZERO;
case 0x7ff: return m ? FP_NAN : FP_INFINITE;
}
}
int xisinf(double d)
{
return isinf(d);
return FP_INFINITE == xfpclassify(d);
}
int xisnan(double d)
{
#if defined(__MINGW32__)
// Workaround mingw warning. #7863
return _isnan(d);
#else
return isnan(d);
#endif
return FP_NAN == xfpclassify(d);
}
#if defined(__clang__) && __clang__ == 1 && __clang_major__ >= 6
# pragma clang diagnostic pop
#endif