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 <cstring> 50 : 51 : /************************************************************************/ 52 : /* HalfToFloat() */ 53 : /* */ 54 : /* 16-bit floating point number to 32-bit one. */ 55 : /************************************************************************/ 56 : 57 162020 : GUInt32 CPLHalfToFloat(GUInt16 iHalf) 58 : { 59 : 60 162020 : GUInt32 iSign = (iHalf >> 15) & 0x00000001; 61 162020 : int iExponent = (iHalf >> 10) & 0x0000001f; 62 162020 : GUInt32 iMantissa = iHalf & 0x000003ff; 63 : 64 162020 : if (iExponent == 0) 65 : { 66 261 : if (iMantissa == 0) 67 : { 68 : /* -------------------------------------------------------------------- 69 : */ 70 : /* Plus or minus zero. */ 71 : /* -------------------------------------------------------------------- 72 : */ 73 : 74 256 : return iSign << 31; 75 : } 76 : else 77 : { 78 : /* -------------------------------------------------------------------- 79 : */ 80 : /* Denormalized number -- renormalize it. */ 81 : /* -------------------------------------------------------------------- 82 : */ 83 : 84 37 : while (!(iMantissa & 0x00000400)) 85 : { 86 32 : iMantissa <<= 1; 87 32 : iExponent -= 1; 88 : } 89 : 90 5 : iExponent += 1; 91 5 : iMantissa &= ~0x00000400U; 92 : } 93 : } 94 161759 : else if (iExponent == 31) 95 : { 96 11 : if (iMantissa == 0) 97 : { 98 : /* -------------------------------------------------------------------- 99 : */ 100 : /* Positive or negative infinity. */ 101 : /* -------------------------------------------------------------------- 102 : */ 103 : 104 5 : return (iSign << 31) | 0x7f800000; 105 : } 106 : else 107 : { 108 : /* -------------------------------------------------------------------- 109 : */ 110 : /* NaN -- preserve sign and significand bits. */ 111 : /* -------------------------------------------------------------------- 112 : */ 113 : 114 6 : return (iSign << 31) | 0x7f800000 | (iMantissa << 13); 115 : } 116 : } 117 : 118 : /* -------------------------------------------------------------------- */ 119 : /* Normalized number. */ 120 : /* -------------------------------------------------------------------- */ 121 : 122 161753 : iExponent = iExponent + (127 - 15); 123 161753 : iMantissa = iMantissa << 13; 124 : 125 : /* -------------------------------------------------------------------- */ 126 : /* Assemble sign, exponent and mantissa. */ 127 : /* -------------------------------------------------------------------- */ 128 : 129 : /* coverity[overflow_sink] */ 130 161753 : return (iSign << 31) | (static_cast<GUInt32>(iExponent) << 23) | iMantissa; 131 : } 132 : 133 : /************************************************************************/ 134 : /* TripleToFloat() */ 135 : /* */ 136 : /* 24-bit floating point number to 32-bit one. */ 137 : /************************************************************************/ 138 : 139 400 : GUInt32 CPLTripleToFloat(GUInt32 iTriple) 140 : { 141 : 142 400 : GUInt32 iSign = (iTriple >> 23) & 0x00000001; 143 400 : int iExponent = (iTriple >> 16) & 0x0000007f; 144 400 : GUInt32 iMantissa = iTriple & 0x0000ffff; 145 : 146 400 : if (iExponent == 0) 147 : { 148 0 : if (iMantissa == 0) 149 : { 150 : /* -------------------------------------------------------------------- 151 : */ 152 : /* Plus or minus zero. */ 153 : /* -------------------------------------------------------------------- 154 : */ 155 : 156 0 : return iSign << 31; 157 : } 158 : else 159 : { 160 : /* -------------------------------------------------------------------- 161 : */ 162 : /* Denormalized number -- renormalize it. */ 163 : /* -------------------------------------------------------------------- 164 : */ 165 : 166 0 : while (!(iMantissa & 0x00010000)) 167 : { 168 0 : iMantissa <<= 1; 169 0 : iExponent -= 1; 170 : } 171 : 172 0 : iExponent += 1; 173 0 : iMantissa &= ~0x00010000U; 174 : } 175 : } 176 400 : else if (iExponent == 127) 177 : { 178 0 : if (iMantissa == 0) 179 : { 180 : /* -------------------------------------------------------------------- 181 : */ 182 : /* Positive or negative infinity. */ 183 : /* -------------------------------------------------------------------- 184 : */ 185 : 186 0 : return (iSign << 31) | 0x7f800000; 187 : } 188 : else 189 : { 190 : /* -------------------------------------------------------------------- 191 : */ 192 : /* NaN -- preserve sign and significand bits. */ 193 : /* -------------------------------------------------------------------- 194 : */ 195 : 196 0 : return (iSign << 31) | 0x7f800000 | (iMantissa << 7); 197 : } 198 : } 199 : 200 : /* -------------------------------------------------------------------- */ 201 : /* Normalized number. */ 202 : /* -------------------------------------------------------------------- */ 203 : 204 400 : iExponent = iExponent + (127 - 63); 205 400 : iMantissa = iMantissa << 7; 206 : 207 : /* -------------------------------------------------------------------- */ 208 : /* Assemble sign, exponent and mantissa. */ 209 : /* -------------------------------------------------------------------- */ 210 : 211 : /* coverity[overflow_sink] */ 212 400 : return (iSign << 31) | (static_cast<GUInt32>(iExponent) << 23) | iMantissa; 213 : } 214 : 215 : /************************************************************************/ 216 : /* FloatToHalf() */ 217 : /************************************************************************/ 218 : 219 240432 : GUInt16 CPLFloatToHalf(GUInt32 iFloat32, bool &bHasWarned) 220 : { 221 240432 : GUInt32 iSign = (iFloat32 >> 31) & 0x00000001; 222 240432 : GUInt32 iExponent = (iFloat32 >> 23) & 0x000000ff; 223 240432 : GUInt32 iMantissa = iFloat32 & 0x007fffff; 224 : 225 240432 : if (iExponent == 255) 226 : { 227 10 : if (iMantissa == 0) 228 : { 229 : /* -------------------------------------------------------------------- 230 : */ 231 : /* Positive or negative infinity. */ 232 : /* -------------------------------------------------------------------- 233 : */ 234 : 235 4 : return static_cast<GUInt16>((iSign << 15) | 0x7C00); 236 : } 237 : else 238 : { 239 : /* -------------------------------------------------------------------- 240 : */ 241 : /* NaN -- preserve sign and significand bits. */ 242 : /* -------------------------------------------------------------------- 243 : */ 244 6 : if (iMantissa >> 13) 245 4 : return static_cast<GUInt16>((iSign << 15) | 0x7C00 | 246 4 : (iMantissa >> 13)); 247 : 248 2 : return static_cast<GUInt16>((iSign << 15) | 0x7E00); 249 : } 250 : } 251 : 252 240422 : if (iExponent <= 127 - 15) 253 : { 254 : // Zero, float32 denormalized number or float32 too small normalized 255 : // number 256 302 : if (13 + 1 + 127 - 15 - iExponent >= 32) 257 297 : return static_cast<GUInt16>(iSign << 15); 258 : 259 : // Return a denormalized number 260 : return static_cast<GUInt16>( 261 5 : (iSign << 15) | 262 5 : ((iMantissa | 0x00800000) >> (13 + 1 + 127 - 15 - iExponent))); 263 : } 264 240120 : if (iExponent - (127 - 15) >= 31) 265 : { 266 1 : if (!bHasWarned) 267 : { 268 1 : bHasWarned = true; 269 1 : float fVal = 0.0f; 270 1 : memcpy(&fVal, &iFloat32, 4); 271 1 : CPLError( 272 : CE_Failure, CPLE_AppDefined, 273 : "Value %.8g is beyond range of float16. Converted to %sinf", 274 1 : fVal, (fVal > 0) ? "+" : "-"); 275 : } 276 1 : return static_cast<GUInt16>((iSign << 15) | 0x7C00); // Infinity 277 : } 278 : 279 : /* -------------------------------------------------------------------- */ 280 : /* Normalized number. */ 281 : /* -------------------------------------------------------------------- */ 282 : 283 240119 : iExponent = iExponent - (127 - 15); 284 240119 : iMantissa = iMantissa >> 13; 285 : 286 : /* -------------------------------------------------------------------- */ 287 : /* Assemble sign, exponent and mantissa. */ 288 : /* -------------------------------------------------------------------- */ 289 : 290 : // coverity[overflow_sink] 291 240119 : return static_cast<GUInt16>((iSign << 15) | (iExponent << 10) | iMantissa); 292 : } 293 : 294 0 : GUInt16 CPLConvertFloatToHalf(float fFloat32) 295 : { 296 : GUInt32 nFloat32; 297 0 : std::memcpy(&nFloat32, &fFloat32, sizeof nFloat32); 298 0 : bool bHasWarned = true; 299 0 : return CPLFloatToHalf(nFloat32, bHasWarned); 300 : } 301 : 302 0 : float CPLConvertHalfToFloat(GUInt16 nHalf) 303 : { 304 0 : GUInt32 nFloat32 = CPLHalfToFloat(nHalf); 305 : float fFloat32; 306 0 : std::memcpy(&fFloat32, &nFloat32, sizeof fFloat32); 307 0 : return fFloat32; 308 : }