2 * Conversion of f32 to IEEE-754 and vice versa.
4 * © Copyright 2018 Pedro Gimeno Fortea.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "ieee_float.h"
31 // Given an unsigned 32-bit integer representing an IEEE-754 single-precision
32 // float, return the float.
33 f32
u32Tof32Slow(u32 i
)
36 int exp
= (i
>> 23) & 0xFF;
37 u32 sign
= i
& 0x80000000UL
;
38 u32 imant
= i
& 0x7FFFFFUL
;
42 if (std::numeric_limits
<f32
>::has_infinity
)
43 return sign
? -std::numeric_limits
<f32
>::infinity() :
44 std::numeric_limits
<f32
>::infinity();
45 return sign
? std::numeric_limits
<f32
>::max() :
46 std::numeric_limits
<f32
>::lowest();
48 return std::numeric_limits
<f32
>::has_quiet_NaN
?
49 std::numeric_limits
<f32
>::quiet_NaN() : -0.f
;
54 return sign
? -ldexpf((f32
)imant
, -149) : ldexpf((f32
)imant
, -149);
57 return sign
? -ldexpf((f32
)(imant
| 0x800000UL
), exp
- 150) :
58 ldexpf((f32
)(imant
| 0x800000UL
), exp
- 150);
62 // Given a float, return an unsigned 32-bit integer representing the f32
63 // in IEEE-754 single-precision format.
64 u32
f32Tou32Slow(f32 f
)
66 u32 signbit
= std::copysign(1.0f
, f
) == 1.0f
? 0 : 0x80000000UL
;
70 return signbit
| 0x7FC00000UL
;
72 return signbit
| 0x7F800000UL
;
73 int exp
= 0; // silence warning
74 f32 mant
= frexpf(f
, &exp
);
75 u32 imant
= (u32
)std::floor((signbit
? -16777216.f
: 16777216.f
) * mant
);
79 return signbit
| (exp
<= -31 ? 0 : imant
>> (1 - exp
));
83 // Overflow due to the platform having exponents bigger than IEEE ones.
84 // Return signed infinity.
85 return signbit
| 0x7F800000UL
;
89 return signbit
| (exp
<< 23) | (imant
& 0x7FFFFFUL
);
92 // This test needs the following requisites in order to work:
93 // - The float type must be a 32 bits IEEE-754 single-precision float.
94 // - The endianness of f32s and integers must match.
95 FloatType
getFloatSerializationType()
98 const f32 cf
= -22220490.f
;
99 const u32 cu
= 0xCBA98765UL
;
100 if (std::numeric_limits
<f32
>::is_iec559
&& sizeof(cf
) == 4 &&
101 sizeof(cu
) == 4 && !memcmp(&cf
, &cu
, 4)) {
102 // u32Tof32Slow and f32Tou32Slow are not needed, use memcpy
103 return FLOATTYPE_SYSTEM
;
106 // Run quick tests to ensure the custom functions provide acceptable results
107 warningstream
<< "floatSerialization: f32 and u32 endianness are "
108 "not equal or machine is not IEEE-754 compliant" << std::endl
;
112 // NaN checks aren't included in the main loop
113 if (!std::isnan(u32Tof32Slow(0x7FC00000UL
))) {
114 porting::mt_snprintf(buf
, sizeof(buf
),
115 "u32Tof32Slow(0x7FC00000) failed to produce a NaN, actual: %.9g",
116 u32Tof32Slow(0x7FC00000UL
));
117 infostream
<< buf
<< std::endl
;
119 if (!std::isnan(u32Tof32Slow(0xFFC00000UL
))) {
120 porting::mt_snprintf(buf
, sizeof(buf
),
121 "u32Tof32Slow(0xFFC00000) failed to produce a NaN, actual: %.9g",
122 u32Tof32Slow(0xFFC00000UL
));
123 infostream
<< buf
<< std::endl
;
126 i
= f32Tou32Slow(std::numeric_limits
<f32
>::quiet_NaN());
127 // check that it corresponds to a NaN encoding
128 if ((i
& 0x7F800000UL
) != 0x7F800000UL
|| (i
& 0x7FFFFFUL
) == 0) {
129 porting::mt_snprintf(buf
, sizeof(buf
),
130 "f32Tou32Slow(NaN) failed to encode NaN, actual: 0x%X", i
);
131 infostream
<< buf
<< std::endl
;
134 return FLOATTYPE_SLOW
;