LCOV - code coverage report
Current view: top level - port - cpl_float.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 75 131 57.3 %
Date: 2025-05-24 03:54:53 Functions: 4 7 57.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL
       4             :  * Purpose:  Floating point conversion functions. Convert 16- and 24-bit
       5             :  *           floating point numbers into the 32-bit IEEE 754 compliant ones.
       6             :  * Author:   Andrey Kiselev, dron@remotesensing.org
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2005, Andrey Kiselev <dron@remotesensing.org>
      10             :  *
      11             :  * This code is based on the code from OpenEXR project with the following
      12             :  * copyright:
      13             :  *
      14             :  * Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
      15             :  * Digital Ltd. LLC
      16             :  *
      17             :  * All rights reserved.
      18             :  *
      19             :  * Redistribution and use in source and binary forms, with or without
      20             :  * modification, are permitted provided that the following conditions are
      21             :  * met:
      22             :  * *       Redistributions of source code must retain the above copyright
      23             :  * notice, this list of conditions and the following disclaimer.
      24             :  * *       Redistributions in binary form must reproduce the above
      25             :  * copyright notice, this list of conditions and the following disclaimer
      26             :  * in the documentation and/or other materials provided with the
      27             :  * distribution.
      28             :  * *       Neither the name of Industrial Light & Magic nor the names of
      29             :  * its contributors may be used to endorse or promote products derived
      30             :  * from this software without specific prior written permission.
      31             :  *
      32             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      33             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      34             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      35             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      36             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      37             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      38             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      39             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      40             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      41             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      42             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      43             :  *
      44             :  ****************************************************************************/
      45             : 
      46             : #include "cpl_float.h"
      47             : #include "cpl_error.h"
      48             : 
      49             : #include <algorithm>
      50             : #include <cmath>
      51             : #include <cstring>
      52             : #include <limits>
      53             : #include <numeric>
      54             : #include <optional>
      55             : 
      56             : /************************************************************************/
      57             : /*                           HalfToFloat()                              */
      58             : /*                                                                      */
      59             : /*  16-bit floating point number to 32-bit one.                         */
      60             : /************************************************************************/
      61             : 
      62         788 : GUInt32 CPLHalfToFloat(GUInt16 iHalf)
      63             : {
      64             : 
      65         788 :     GUInt32 iSign = (iHalf >> 15) & 0x00000001;
      66         788 :     int iExponent = (iHalf >> 10) & 0x0000001f;
      67         788 :     GUInt32 iMantissa = iHalf & 0x000003ff;
      68             : 
      69         788 :     if (iExponent == 0)
      70             :     {
      71           8 :         if (iMantissa == 0)
      72             :         {
      73             :             /* --------------------------------------------------------------------
      74             :              */
      75             :             /*      Plus or minus zero. */
      76             :             /* --------------------------------------------------------------------
      77             :              */
      78             : 
      79           8 :             return iSign << 31;
      80             :         }
      81             :         else
      82             :         {
      83             :             /* --------------------------------------------------------------------
      84             :              */
      85             :             /*      Denormalized number -- renormalize it. */
      86             :             /* --------------------------------------------------------------------
      87             :              */
      88             : 
      89           0 :             while (!(iMantissa & 0x00000400))
      90             :             {
      91           0 :                 iMantissa <<= 1;
      92           0 :                 iExponent -= 1;
      93             :             }
      94             : 
      95           0 :             iExponent += 1;
      96           0 :             iMantissa &= ~0x00000400U;
      97             :         }
      98             :     }
      99         780 :     else if (iExponent == 31)
     100             :     {
     101           0 :         if (iMantissa == 0)
     102             :         {
     103             :             /* --------------------------------------------------------------------
     104             :              */
     105             :             /*       Positive or negative infinity. */
     106             :             /* --------------------------------------------------------------------
     107             :              */
     108             : 
     109           0 :             return (iSign << 31) | 0x7f800000;
     110             :         }
     111             :         else
     112             :         {
     113             :             /* --------------------------------------------------------------------
     114             :              */
     115             :             /*       NaN -- preserve sign and significand bits. */
     116             :             /* --------------------------------------------------------------------
     117             :              */
     118             : 
     119           0 :             return (iSign << 31) | 0x7f800000 | (iMantissa << 13);
     120             :         }
     121             :     }
     122             : 
     123             :     /* -------------------------------------------------------------------- */
     124             :     /*       Normalized number.                                             */
     125             :     /* -------------------------------------------------------------------- */
     126             : 
     127         780 :     iExponent = iExponent + (127 - 15);
     128         780 :     iMantissa = iMantissa << 13;
     129             : 
     130             :     /* -------------------------------------------------------------------- */
     131             :     /*       Assemble sign, exponent and mantissa.                          */
     132             :     /* -------------------------------------------------------------------- */
     133             : 
     134             :     /* coverity[overflow_sink] */
     135         780 :     return (iSign << 31) | (static_cast<GUInt32>(iExponent) << 23) | iMantissa;
     136             : }
     137             : 
     138             : /************************************************************************/
     139             : /*                           TripleToFloat()                            */
     140             : /*                                                                      */
     141             : /*  24-bit floating point number to 32-bit one.                         */
     142             : /************************************************************************/
     143             : 
     144         400 : GUInt32 CPLTripleToFloat(GUInt32 iTriple)
     145             : {
     146             : 
     147         400 :     GUInt32 iSign = (iTriple >> 23) & 0x00000001;
     148         400 :     int iExponent = (iTriple >> 16) & 0x0000007f;
     149         400 :     GUInt32 iMantissa = iTriple & 0x0000ffff;
     150             : 
     151         400 :     if (iExponent == 0)
     152             :     {
     153           0 :         if (iMantissa == 0)
     154             :         {
     155             :             /* --------------------------------------------------------------------
     156             :              */
     157             :             /*      Plus or minus zero. */
     158             :             /* --------------------------------------------------------------------
     159             :              */
     160             : 
     161           0 :             return iSign << 31;
     162             :         }
     163             :         else
     164             :         {
     165             :             /* --------------------------------------------------------------------
     166             :              */
     167             :             /*      Denormalized number -- renormalize it. */
     168             :             /* --------------------------------------------------------------------
     169             :              */
     170             : 
     171           0 :             while (!(iMantissa & 0x00010000))
     172             :             {
     173           0 :                 iMantissa <<= 1;
     174           0 :                 iExponent -= 1;
     175             :             }
     176             : 
     177           0 :             iExponent += 1;
     178           0 :             iMantissa &= ~0x00010000U;
     179             :         }
     180             :     }
     181         400 :     else if (iExponent == 127)
     182             :     {
     183           0 :         if (iMantissa == 0)
     184             :         {
     185             :             /* --------------------------------------------------------------------
     186             :              */
     187             :             /*       Positive or negative infinity. */
     188             :             /* --------------------------------------------------------------------
     189             :              */
     190             : 
     191           0 :             return (iSign << 31) | 0x7f800000;
     192             :         }
     193             :         else
     194             :         {
     195             :             /* --------------------------------------------------------------------
     196             :              */
     197             :             /*       NaN -- preserve sign and significand bits. */
     198             :             /* --------------------------------------------------------------------
     199             :              */
     200             : 
     201           0 :             return (iSign << 31) | 0x7f800000 | (iMantissa << 7);
     202             :         }
     203             :     }
     204             : 
     205             :     /* -------------------------------------------------------------------- */
     206             :     /*       Normalized number.                                             */
     207             :     /* -------------------------------------------------------------------- */
     208             : 
     209         400 :     iExponent = iExponent + (127 - 63);
     210         400 :     iMantissa = iMantissa << 7;
     211             : 
     212             :     /* -------------------------------------------------------------------- */
     213             :     /*       Assemble sign, exponent and mantissa.                          */
     214             :     /* -------------------------------------------------------------------- */
     215             : 
     216             :     /* coverity[overflow_sink] */
     217         400 :     return (iSign << 31) | (static_cast<GUInt32>(iExponent) << 23) | iMantissa;
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*                            FloatToHalf()                             */
     222             : /************************************************************************/
     223             : 
     224           0 : GUInt16 CPLFloatToHalf(GUInt32 iFloat32, bool &bHasWarned)
     225             : {
     226           0 :     GUInt32 iSign = (iFloat32 >> 31) & 0x00000001;
     227           0 :     GUInt32 iExponent = (iFloat32 >> 23) & 0x000000ff;
     228           0 :     GUInt32 iMantissa = iFloat32 & 0x007fffff;
     229             : 
     230           0 :     if (iExponent == 255)
     231             :     {
     232           0 :         if (iMantissa == 0)
     233             :         {
     234             :             /* --------------------------------------------------------------------
     235             :              */
     236             :             /*       Positive or negative infinity. */
     237             :             /* --------------------------------------------------------------------
     238             :              */
     239             : 
     240           0 :             return static_cast<GUInt16>((iSign << 15) | 0x7C00);
     241             :         }
     242             :         else
     243             :         {
     244             :             /* --------------------------------------------------------------------
     245             :              */
     246             :             /*       NaN -- preserve sign and significand bits. */
     247             :             /* --------------------------------------------------------------------
     248             :              */
     249           0 :             if (iMantissa >> 13)
     250           0 :                 return static_cast<GUInt16>((iSign << 15) | 0x7C00 |
     251           0 :                                             (iMantissa >> 13));
     252             : 
     253           0 :             return static_cast<GUInt16>((iSign << 15) | 0x7E00);
     254             :         }
     255             :     }
     256             : 
     257           0 :     if (iExponent <= 127 - 15)
     258             :     {
     259             :         // Zero, float32 denormalized number or float32 too small normalized
     260             :         // number
     261           0 :         if (13 + 1 + 127 - 15 - iExponent >= 32)
     262           0 :             return static_cast<GUInt16>(iSign << 15);
     263             : 
     264             :         // Return a denormalized number
     265             :         return static_cast<GUInt16>(
     266           0 :             (iSign << 15) |
     267           0 :             ((iMantissa | 0x00800000) >> (13 + 1 + 127 - 15 - iExponent)));
     268             :     }
     269           0 :     if (iExponent - (127 - 15) >= 31)
     270             :     {
     271           0 :         if (!bHasWarned)
     272             :         {
     273           0 :             bHasWarned = true;
     274           0 :             float fVal = 0.0f;
     275           0 :             memcpy(&fVal, &iFloat32, 4);
     276           0 :             CPLError(
     277             :                 CE_Failure, CPLE_AppDefined,
     278             :                 "Value %.8g is beyond range of float16. Converted to %sinf",
     279           0 :                 fVal, (fVal > 0) ? "+" : "-");
     280             :         }
     281           0 :         return static_cast<GUInt16>((iSign << 15) | 0x7C00);  // Infinity
     282             :     }
     283             : 
     284             :     /* -------------------------------------------------------------------- */
     285             :     /*       Normalized number.                                             */
     286             :     /* -------------------------------------------------------------------- */
     287             : 
     288           0 :     iExponent = iExponent - (127 - 15);
     289           0 :     iMantissa = iMantissa >> 13;
     290             : 
     291             :     /* -------------------------------------------------------------------- */
     292             :     /*       Assemble sign, exponent and mantissa.                          */
     293             :     /* -------------------------------------------------------------------- */
     294             : 
     295             :     // coverity[overflow_sink]
     296           0 :     return static_cast<GUInt16>((iSign << 15) | (iExponent << 10) | iMantissa);
     297             : }
     298             : 
     299           0 : GUInt16 CPLConvertFloatToHalf(float fFloat32)
     300             : {
     301             :     GUInt32 nFloat32;
     302           0 :     std::memcpy(&nFloat32, &fFloat32, sizeof nFloat32);
     303           0 :     bool bHasWarned = true;
     304           0 :     return CPLFloatToHalf(nFloat32, bHasWarned);
     305             : }
     306             : 
     307           0 : float CPLConvertHalfToFloat(GUInt16 nHalf)
     308             : {
     309           0 :     GUInt32 nFloat32 = CPLHalfToFloat(nHalf);
     310             :     float fFloat32;
     311           0 :     std::memcpy(&fFloat32, &nFloat32, sizeof fFloat32);
     312           0 :     return fFloat32;
     313             : }
     314             : 
     315             : namespace
     316             : {
     317             : 
     318             : template <typename T> struct Fraction
     319             : {
     320             :     using value_type = T;
     321             : 
     322             :     T num;
     323             :     T denom;
     324             : };
     325             : 
     326             : /** Approximate a floating point number as a fraction, using the method describe
     327             :  * in Richards, Ian (1981). Continued Fractions Without Tears. Mathematics
     328             :  * Magazine, Vol. 54, No. 4. https://doi.org/10.2307/2689627
     329             :  *
     330             :  * If the fraction cannot be approximated within the specified error tolerance
     331             :  * in a certain amount of iterations, a warning will be raised and  std::nullopt
     332             :  * will be returned.
     333             :  *
     334             :  * @param x the number to approximate as a fraction
     335             :  * @param err the maximum allowable absolute error in the approximation
     336             :  *
     337             :  * @return the approximated value, or std::nullopt
     338             :  *
     339             : */
     340          64 : std::optional<Fraction<std::uint64_t>> FloatToFraction(double x, double err)
     341             : {
     342             :     using inttype = std::uint64_t;
     343          64 :     constexpr int MAX_ITER = 1000;
     344             : 
     345          64 :     const double sign = std::signbit(x) ? -1 : 1;
     346             : 
     347          64 :     double g(std::abs(x));
     348          64 :     inttype a(0);
     349          64 :     inttype b(1);
     350          64 :     inttype c(1);
     351          64 :     inttype d(0);
     352             : 
     353             :     Fraction<std::uint64_t> ret;
     354             : 
     355         118 :     for (int i = 0; i < MAX_ITER; i++)
     356             :     {
     357         236 :         if (!(g >= 0 &&
     358         118 :               g <= static_cast<double>(std::numeric_limits<inttype>::max())))
     359             :         {
     360           1 :             break;
     361             :         }
     362         117 :         const inttype s = static_cast<inttype>(std::floor(g));
     363         117 :         ret.num = a + s * c;
     364         117 :         ret.denom = b + s * d;
     365             : 
     366         117 :         a = c;
     367         117 :         b = d;
     368         117 :         c = ret.num;
     369         117 :         d = ret.denom;
     370         117 :         g = 1.0 / (g - static_cast<double>(s));
     371             : 
     372         117 :         const double approx = sign * static_cast<double>(ret.num) /
     373         117 :                               static_cast<double>(ret.denom);
     374             : 
     375         117 :         if (std::abs(approx - x) < err)
     376             :         {
     377          63 :             return ret;
     378             :         }
     379             :     }
     380             : 
     381           1 :     CPLError(CE_Warning, CPLE_AppDefined,
     382             :              "Failed to approximate %g as a fraction with error < %g in %d "
     383             :              "iterations",
     384             :              x, err, MAX_ITER);
     385           1 :     return std::nullopt;
     386             : }
     387             : }  // namespace
     388             : 
     389             : /** Return the largest value by which two input values can be
     390             :  *  divided, with the result being an integer. If no suitable
     391             :  *  value can be found, zero will be returned.
     392             :  */
     393          47 : double CPLGreatestCommonDivisor(double a, double b)
     394             : {
     395          47 :     if (a == 0 || !std::isfinite(a) || b == 0 || !std::isfinite(b))
     396             :     {
     397           8 :         CPLError(CE_Failure, CPLE_AppDefined,
     398             :                  "Input values must be finite non-null values");
     399           8 :         return 0;
     400             :     }
     401             : 
     402          39 :     if (a == b)
     403             :     {
     404           0 :         return a;
     405             :     }
     406             : 
     407             :     // Check if one resolution is an integer factor of the other.
     408             :     // This is fast and succeeds in some cases where the method below fails.
     409          39 :     if (a > b && std::abs(std::round(a / b) - a / b) < 1e-8)
     410             :     {
     411           3 :         return b;
     412             :     }
     413          36 :     if (b > a && std::abs(std::round(b / a) - b / a) < 1e-8)
     414             :     {
     415           4 :         return a;
     416             :     }
     417             : 
     418          32 :     const auto approx_a = FloatToFraction(a, 1e-10);
     419          32 :     if (!approx_a.has_value())
     420             :     {
     421           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     422             :                  "Could not approximate resolution %.18g as a fraction", a);
     423           0 :         return 0;
     424             :     }
     425             : 
     426          32 :     const auto approx_b = FloatToFraction(b, 1e-10);
     427          32 :     if (!approx_b.has_value())
     428             :     {
     429           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     430             :                  "Could not approximate resolution %.18g as a fraction", b);
     431           1 :         return 0;
     432             :     }
     433             : 
     434          31 :     const double sign = std::signbit(a) ? -1 : 1;
     435             : 
     436          31 :     const auto &frac_a = approx_a.value();
     437          31 :     const auto &frac_b = approx_b.value();
     438             : 
     439          31 :     const auto common_denom = std::lcm(frac_a.denom, frac_b.denom);
     440             : 
     441             :     const auto num_a = static_cast<std::uint64_t>(
     442          31 :         frac_a.num * std::round(common_denom / frac_a.denom));
     443             :     const auto num_b = static_cast<std::uint64_t>(
     444          31 :         frac_b.num * std::round(common_denom / frac_b.denom));
     445             : 
     446          31 :     const auto common_num = std::gcd(num_a, num_b);
     447             : 
     448             :     // coverity[divide_by_zero]
     449          31 :     const auto common = sign * static_cast<double>(common_num) /
     450          31 :                         static_cast<double>(common_denom);
     451             : 
     452          31 :     const auto disaggregation_factor = std::max(a / common, b / common);
     453          31 :     if (disaggregation_factor > 10000)
     454             :     {
     455           4 :         CPLError(CE_Failure, CPLE_AppDefined,
     456             :                  "Common resolution between %.18g and %.18g calculated at "
     457             :                  "%.18g which "
     458             :                  "would cause excessive disaggregation",
     459             :                  a, b, common);
     460           4 :         return 0;
     461             :     }
     462             : 
     463          27 :     return common;
     464             : }

Generated by: LCOV version 1.14