LCOV - code coverage report
Current view: top level - autotest/cpp - testfloat16.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 94 95 98.9 %
Date: 2025-07-09 17:50:03 Functions: 17 17 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * $Id$
       3             :  *
       4             :  * Project:  GDAL Core
       5             :  * Purpose:  Test GFloat16.
       6             :  * Author:   Erik Schnetter <eschnetter at perimeterinstitute.ca>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_float.h"
      15             : 
      16             : #include "gtest_include.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <cmath>
      20             : #include <limits>
      21             : 
      22             : namespace
      23             : {
      24             : 
      25           4 : TEST(TestFloat16, conversions)
      26             : {
      27        4098 :     for (int i = -2048; i <= +2048; ++i)
      28             :     {
      29        4097 :         EXPECT_EQ(GFloat16(i), static_cast<double>(i));
      30        4097 :         if (i >= -128 && i <= 127)
      31             :         {
      32         256 :             EXPECT_EQ(GFloat16(static_cast<signed char>(i)),
      33             :                       static_cast<double>(i));
      34             :         }
      35        4097 :         EXPECT_EQ(GFloat16(static_cast<short>(i)), static_cast<double>(i));
      36        4097 :         EXPECT_EQ(GFloat16(static_cast<int>(i)), static_cast<double>(i));
      37        4097 :         EXPECT_EQ(GFloat16(static_cast<long>(i)), static_cast<double>(i));
      38        4097 :         EXPECT_EQ(GFloat16(static_cast<long long>(i)), static_cast<double>(i));
      39        4097 :         if (i >= 0)
      40             :         {
      41        2049 :             if (i <= 255)
      42             :             {
      43         256 :                 EXPECT_EQ(GFloat16(static_cast<unsigned char>(i)),
      44             :                           static_cast<double>(i));
      45             :             }
      46        2049 :             EXPECT_EQ(GFloat16(static_cast<unsigned short>(i)),
      47             :                       static_cast<double>(i));
      48        2049 :             EXPECT_EQ(GFloat16(static_cast<unsigned>(i)),
      49             :                       static_cast<double>(i));
      50        2049 :             EXPECT_EQ(GFloat16(static_cast<unsigned long>(i)),
      51             :                       static_cast<double>(i));
      52        2049 :             EXPECT_EQ(GFloat16(static_cast<unsigned long long>(i)),
      53             :                       static_cast<double>(i));
      54             :         }
      55        4097 :         EXPECT_EQ(GFloat16(i), GFloat16(i));
      56        4097 :         EXPECT_EQ(GFloat16(i), static_cast<double>(i));
      57             :     }
      58             : 
      59           1 :     EXPECT_EQ(GFloat16(65504), 65504.0);
      60           1 :     EXPECT_EQ(GFloat16(-65504), -65504.0);
      61             :     // Work around the Windows compiler reporting "error C2124: divide
      62             :     // or mod by zero". See also
      63             :     // <https://stackoverflow.com/questions/3082508/msvc-erroring-on-a-divide-by-0-that-will-never-happen-fix>.
      64           1 :     volatile double zero = 0.0;
      65           1 :     EXPECT_EQ(GFloat16(1.0 / zero), 1.0 / zero);
      66           1 :     EXPECT_EQ(GFloat16(-1.0 / zero), -1.0 / zero);
      67           1 :     EXPECT_EQ(GFloat16(0.0), -0.0);
      68           1 :     EXPECT_EQ(GFloat16(-0.0), 0.0);
      69           1 : }
      70             : 
      71           4 : TEST(TestFloat16, arithmetic)
      72             : {
      73         202 :     for (int i = -100; i <= +100; ++i)
      74             :     {
      75         201 :         double x = i;
      76             : 
      77         201 :         EXPECT_EQ(+GFloat16(x), +x);
      78         201 :         EXPECT_EQ(-GFloat16(x), -x);
      79             :     }
      80             : 
      81         202 :     for (int i = -100; i <= +100; ++i)
      82             :     {
      83       40602 :         for (int j = -100; j <= +100; ++j)
      84             :         {
      85       40401 :             double x = i;
      86       40401 :             double y = j;
      87             : 
      88       40401 :             EXPECT_EQ(GFloat16(x) + GFloat16(y), x + y);
      89       40401 :             EXPECT_EQ(GFloat16(x) - GFloat16(y), x - y);
      90             :             using std::fabs;
      91       40401 :             EXPECT_NEAR(GFloat16(x) * GFloat16(y), x * y, fabs(x * y / 1024));
      92       40401 :             if (j != 0)
      93             :             {
      94       40200 :                 EXPECT_NEAR(GFloat16(x) / GFloat16(y), x / y,
      95             :                             fabs(x / y / 1024));
      96             :             }
      97             :         }
      98             :     }
      99           1 : }
     100             : 
     101           4 : TEST(TestFloat16, comparisons)
     102             : {
     103         202 :     for (int i = -100; i <= +100; ++i)
     104             :     {
     105       40602 :         for (int j = -100; j <= +100; ++j)
     106             :         {
     107       40401 :             double x = i;
     108       40401 :             double y = j;
     109             : 
     110       40401 :             EXPECT_EQ(GFloat16(x) == GFloat16(y), x == y);
     111       40401 :             EXPECT_EQ(GFloat16(x) != GFloat16(y), x != y);
     112       40401 :             EXPECT_EQ(GFloat16(x) < GFloat16(y), x < y);
     113       40401 :             EXPECT_EQ(GFloat16(x) > GFloat16(y), x > y);
     114       40401 :             EXPECT_EQ(GFloat16(x) <= GFloat16(y), x <= y);
     115       40401 :             EXPECT_EQ(GFloat16(x) >= GFloat16(y), x >= y);
     116             :         }
     117             :     }
     118           1 : }
     119             : 
     120           4 : TEST(TestFloat16, math)
     121             : {
     122         202 :     for (int i = -100; i <= +100; ++i)
     123             :     {
     124         201 :         const double x = i;
     125             : 
     126             :         using std::isfinite;
     127         201 :         EXPECT_EQ(isfinite(GFloat16(x)), isfinite(x));
     128             :         using std::isinf;
     129         201 :         EXPECT_EQ(isinf(GFloat16(x)), isinf(x));
     130             :         using std::isnan;
     131         201 :         EXPECT_EQ(isnan(GFloat16(x)), isnan(x));
     132             :         using std::abs;
     133         201 :         EXPECT_EQ(abs(GFloat16(x)), abs(x));
     134             :         using std::cbrt;
     135             :         using std::fabs;
     136         201 :         EXPECT_NEAR(cbrt(GFloat16(x)), cbrt(x), fabs(cbrt(x) / 1024));
     137             :         using std::ceil;
     138         201 :         EXPECT_EQ(ceil(GFloat16(x)), ceil(x));
     139             :         using std::fabs;
     140         201 :         EXPECT_EQ(fabs(GFloat16(x)), fabs(x));
     141             :         using std::floor;
     142         201 :         EXPECT_EQ(floor(GFloat16(x)), floor(x));
     143             :         using std::round;
     144         201 :         EXPECT_EQ(round(GFloat16(x)), round(x));
     145             :     }
     146         102 :     for (int i = 0; i <= 100; ++i)
     147             :     {
     148         101 :         const double x = i;
     149             :         using std::sqrt;
     150         101 :         EXPECT_NEAR(sqrt(GFloat16(x)), sqrt(x), fabs(sqrt(x) / 1024));
     151             :     }
     152             : 
     153             :     // To avoid Coverity Scan false positive about first value not positive...
     154       80802 :     const auto myPow = [](int a, int b)
     155             :     {
     156       80802 :         double res = 1.0;
     157     4141000 :         for (int k = 0; k < std::abs(b); ++k)
     158     4060200 :             res *= a;
     159       80802 :         if (b >= 0)
     160       40602 :             return res;
     161       40200 :         else if (a == 0)
     162         200 :             return std::numeric_limits<double>::infinity();
     163             :         else
     164       40000 :             return 1.0 / res;
     165             :     };
     166             : 
     167         202 :     for (int i = -100; i <= +100; ++i)
     168             :     {
     169       40602 :         for (int j = -100; j <= +100; ++j)
     170             :         {
     171       40401 :             const double x = i;
     172       40401 :             const double y = j;
     173             : 
     174             :             using std::fmax;
     175       40401 :             EXPECT_EQ(fmax(GFloat16(x), GFloat16(y)), GFloat16(fmax(x, y)));
     176             :             using std::fmin;
     177       40401 :             EXPECT_EQ(fmin(GFloat16(x), GFloat16(y)), GFloat16(fmin(x, y)));
     178             :             using std::hypot;
     179       40401 :             EXPECT_EQ(hypot(GFloat16(x), GFloat16(y)), GFloat16(hypot(x, y)));
     180             :             using std::max;
     181       40401 :             EXPECT_EQ(max(GFloat16(x), GFloat16(y)), GFloat16(max(x, y)));
     182             :             using std::min;
     183       40401 :             EXPECT_EQ(min(GFloat16(x), GFloat16(y)), GFloat16(min(x, y)));
     184             :             using std::pow;
     185       40401 :             EXPECT_EQ(pow(GFloat16(x), GFloat16(y)), GFloat16(myPow(i, j)))
     186           0 :                 << "i=" << i << ", j=" << j;
     187             :             using std::fabs;
     188             :             using std::isfinite;
     189       40401 :             GFloat16 r1 = GFloat16(pow(GFloat16(x), j));
     190       40401 :             GFloat16 r2 = GFloat16(myPow(i, j));
     191       40401 :             if (!isfinite(r1))
     192             :             {
     193       19344 :                 EXPECT_EQ(r1, r2);
     194             :             }
     195             :             else
     196             :             {
     197       21057 :                 GFloat16 tol = (1 + fabs(r2)) / 1024;
     198       21057 :                 EXPECT_NEAR(r1, r2, tol);
     199             :             }
     200             :         }
     201             :     }
     202           1 : }
     203             : 
     204             : }  // namespace

Generated by: LCOV version 1.14