xref: /aosp_15_r20/external/mesa3d/src/util/double.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker  * Mesa 3-D graphics library
3*61046927SAndroid Build Coastguard Worker  *
4*61046927SAndroid Build Coastguard Worker  * Copyright (C) 2018-2019 Intel Corporation
5*61046927SAndroid Build Coastguard Worker  *
6*61046927SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
7*61046927SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
8*61046927SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
9*61046927SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*61046927SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
11*61046927SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
12*61046927SAndroid Build Coastguard Worker  *
13*61046927SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included
14*61046927SAndroid Build Coastguard Worker  * in all copies or substantial portions of the Software.
15*61046927SAndroid Build Coastguard Worker  *
16*61046927SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17*61046927SAndroid Build Coastguard Worker  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*61046927SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*61046927SAndroid Build Coastguard Worker  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20*61046927SAndroid Build Coastguard Worker  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21*61046927SAndroid Build Coastguard Worker  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22*61046927SAndroid Build Coastguard Worker  * OTHER DEALINGS IN THE SOFTWARE.
23*61046927SAndroid Build Coastguard Worker  */
24*61046927SAndroid Build Coastguard Worker 
25*61046927SAndroid Build Coastguard Worker #ifndef _DOUBLE_H_
26*61046927SAndroid Build Coastguard Worker #define _DOUBLE_H_
27*61046927SAndroid Build Coastguard Worker 
28*61046927SAndroid Build Coastguard Worker #include "half_float.h"
29*61046927SAndroid Build Coastguard Worker #include "u_math.h"
30*61046927SAndroid Build Coastguard Worker 
31*61046927SAndroid Build Coastguard Worker #ifdef __cplusplus
32*61046927SAndroid Build Coastguard Worker extern "C" {
33*61046927SAndroid Build Coastguard Worker #endif
34*61046927SAndroid Build Coastguard Worker 
35*61046927SAndroid Build Coastguard Worker /*
36*61046927SAndroid Build Coastguard Worker  * This API is no more than a wrapper to the counterpart softfloat.h
37*61046927SAndroid Build Coastguard Worker  * calls. Still, softfloat.h conversion API is meant to be kept private. In
38*61046927SAndroid Build Coastguard Worker  * other words, only use the API published here, instead of calling directly
39*61046927SAndroid Build Coastguard Worker  * the softfloat.h one.
40*61046927SAndroid Build Coastguard Worker  */
41*61046927SAndroid Build Coastguard Worker 
42*61046927SAndroid Build Coastguard Worker float _mesa_double_to_float(double val);
43*61046927SAndroid Build Coastguard Worker float _mesa_double_to_float_rtz(double val);
44*61046927SAndroid Build Coastguard Worker 
45*61046927SAndroid Build Coastguard Worker static inline float
_mesa_double_to_float_rtne(double val)46*61046927SAndroid Build Coastguard Worker _mesa_double_to_float_rtne(double val)
47*61046927SAndroid Build Coastguard Worker {
48*61046927SAndroid Build Coastguard Worker    return _mesa_double_to_float(val);
49*61046927SAndroid Build Coastguard Worker }
50*61046927SAndroid Build Coastguard Worker 
51*61046927SAndroid Build Coastguard Worker /*
52*61046927SAndroid Build Coastguard Worker  * We round down from double to half float by going through float in between,
53*61046927SAndroid Build Coastguard Worker  * but this can give us inaccurate results in some cases.
54*61046927SAndroid Build Coastguard Worker  * One such case is 0x40ee6a0000000001, which should round to 0x7b9b, but
55*61046927SAndroid Build Coastguard Worker  * going through float first turns into 0x7b9a instead. This is because the
56*61046927SAndroid Build Coastguard Worker  * first non-fitting bit is set, so we get a tie, but with the least
57*61046927SAndroid Build Coastguard Worker  * significant bit of the original number set, the tie should break rounding
58*61046927SAndroid Build Coastguard Worker  * up.
59*61046927SAndroid Build Coastguard Worker  * The cast to float, however, turns into 0x47735000, which when going to half
60*61046927SAndroid Build Coastguard Worker  * still ties, but now we lost the tie-up bit, and instead we round to the
61*61046927SAndroid Build Coastguard Worker  * nearest even, which in this case is down.
62*61046927SAndroid Build Coastguard Worker  *
63*61046927SAndroid Build Coastguard Worker  * To fix this, we check if the original would have tied, and if the tie would
64*61046927SAndroid Build Coastguard Worker  * have rounded up, and if both are true, set the least significant bit of the
65*61046927SAndroid Build Coastguard Worker  * intermediate float to 1, so that a tie on the next cast rounds up as well.
66*61046927SAndroid Build Coastguard Worker  * If the rounding already got rid of the tie, that set bit will just be
67*61046927SAndroid Build Coastguard Worker  * truncated anyway and the end result doesn't change.
68*61046927SAndroid Build Coastguard Worker  *
69*61046927SAndroid Build Coastguard Worker  * Another failing case is 0x40effdffffffffff. This one doesn't have the tie
70*61046927SAndroid Build Coastguard Worker  * from double to half, so it just rounds down to 0x7bff (65504.0), but going
71*61046927SAndroid Build Coastguard Worker  * through float first, it turns into 0x477ff000, which does have the tie bit
72*61046927SAndroid Build Coastguard Worker  * for half set, and when that one gets rounded it turns into 0x7c00
73*61046927SAndroid Build Coastguard Worker  * (Infinity).
74*61046927SAndroid Build Coastguard Worker  * The fix for that one is to make sure the intermediate float does not have
75*61046927SAndroid Build Coastguard Worker  * the tie bit set if the original didn't have it.
76*61046927SAndroid Build Coastguard Worker  */
77*61046927SAndroid Build Coastguard Worker static inline uint16_t
_mesa_double_to_float16_rtne(double val)78*61046927SAndroid Build Coastguard Worker _mesa_double_to_float16_rtne(double val)
79*61046927SAndroid Build Coastguard Worker {
80*61046927SAndroid Build Coastguard Worker    int significand_bits16 = 10;
81*61046927SAndroid Build Coastguard Worker    int significand_bits32 = 23;
82*61046927SAndroid Build Coastguard Worker    int significand_bits64 = 52;
83*61046927SAndroid Build Coastguard Worker    int f64_to_16_tie_bit = significand_bits64 - significand_bits16 - 1;
84*61046927SAndroid Build Coastguard Worker    int f32_to_16_tie_bit = significand_bits32 - significand_bits16 - 1;
85*61046927SAndroid Build Coastguard Worker    uint64_t f64_rounds_up_mask = ((1ULL << f64_to_16_tie_bit) - 1);
86*61046927SAndroid Build Coastguard Worker 
87*61046927SAndroid Build Coastguard Worker    union di src;
88*61046927SAndroid Build Coastguard Worker    union fi dst;
89*61046927SAndroid Build Coastguard Worker 
90*61046927SAndroid Build Coastguard Worker    src.d = val;
91*61046927SAndroid Build Coastguard Worker    dst.f = val;
92*61046927SAndroid Build Coastguard Worker 
93*61046927SAndroid Build Coastguard Worker    bool f64_has_tie = (src.ui & (1ULL << f64_to_16_tie_bit)) != 0;
94*61046927SAndroid Build Coastguard Worker    bool f64_rounds_up = (src.ui & f64_rounds_up_mask) != 0;
95*61046927SAndroid Build Coastguard Worker 
96*61046927SAndroid Build Coastguard Worker    dst.ui |= (f64_has_tie && f64_rounds_up);
97*61046927SAndroid Build Coastguard Worker    if (!f64_has_tie)
98*61046927SAndroid Build Coastguard Worker       dst.ui &= ~(1U << f32_to_16_tie_bit);
99*61046927SAndroid Build Coastguard Worker 
100*61046927SAndroid Build Coastguard Worker    return _mesa_float_to_float16_rtne(dst.f);
101*61046927SAndroid Build Coastguard Worker }
102*61046927SAndroid Build Coastguard Worker 
103*61046927SAndroid Build Coastguard Worker /*
104*61046927SAndroid Build Coastguard Worker  * double -> float -> half with RTZ doesn't have as many complications as
105*61046927SAndroid Build Coastguard Worker  * RTNE, but we do need to ensure that the double -> float cast also uses RTZ.
106*61046927SAndroid Build Coastguard Worker  */
107*61046927SAndroid Build Coastguard Worker static inline uint16_t
_mesa_double_to_float16_rtz(double val)108*61046927SAndroid Build Coastguard Worker _mesa_double_to_float16_rtz(double val)
109*61046927SAndroid Build Coastguard Worker {
110*61046927SAndroid Build Coastguard Worker    return _mesa_float_to_float16_rtz(_mesa_double_to_float_rtz(val));
111*61046927SAndroid Build Coastguard Worker }
112*61046927SAndroid Build Coastguard Worker 
113*61046927SAndroid Build Coastguard Worker #ifdef __cplusplus
114*61046927SAndroid Build Coastguard Worker } /* extern C */
115*61046927SAndroid Build Coastguard Worker #endif
116*61046927SAndroid Build Coastguard Worker 
117*61046927SAndroid Build Coastguard Worker #endif /* _DOUBLE_H_ */
118