| /************************************************************************** |
| * |
| * Copyright 2010 Luca Barbieri |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sublicense, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial |
| * portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE |
| * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| |
| #ifndef U_HALF_H |
| #define U_HALF_H |
| |
| #include "pipe/p_compiler.h" |
| #include "util/u_math.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* |
| * References for float <-> half conversions |
| * |
| * http://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ |
| * https://gist.github.com/2156668 |
| * https://gist.github.com/2144712 |
| */ |
| |
| static INLINE uint16_t |
| util_float_to_half(float f) |
| { |
| uint32_t sign_mask = 0x80000000; |
| uint32_t round_mask = ~0xfff; |
| uint32_t f32inf = 0xff << 23; |
| uint32_t f16inf = 0x1f << 23; |
| uint32_t sign; |
| union fi magic; |
| union fi f32; |
| uint16_t f16; |
| |
| magic.ui = 0xf << 23; |
| |
| f32.f = f; |
| |
| /* Sign */ |
| sign = f32.ui & sign_mask; |
| f32.ui ^= sign; |
| |
| if (f32.ui == f32inf) { |
| /* Inf */ |
| f16 = 0x7c00; |
| } else if (f32.ui > f32inf) { |
| /* NaN */ |
| f16 = 0x7e00; |
| } else { |
| /* Number */ |
| f32.ui &= round_mask; |
| f32.f *= magic.f; |
| f32.ui -= round_mask; |
| |
| /* Clamp to infinity if overflowed */ |
| if (f32.ui > f16inf) |
| f32.ui = f16inf; |
| |
| f16 = f32.ui >> 13; |
| } |
| |
| /* Sign */ |
| f16 |= sign >> 16; |
| |
| return f16; |
| } |
| |
| static INLINE float |
| util_half_to_float(uint16_t f16) |
| { |
| union fi infnan; |
| union fi magic; |
| union fi f32; |
| |
| infnan.ui = 0x8f << 23; |
| infnan.f = 65536.0f; |
| magic.ui = 0xef << 23; |
| |
| /* Exponent / Mantissa */ |
| f32.ui = (f16 & 0x7fff) << 13; |
| |
| /* Adjust */ |
| f32.f *= magic.f; |
| |
| /* Inf / NaN */ |
| if (f32.f >= infnan.f) |
| f32.ui |= 0xff << 23; |
| |
| /* Sign */ |
| f32.ui |= (f16 & 0x8000) << 16; |
| |
| return f32.f; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* U_HALF_H */ |
| |