1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: MIT (https://spdx.org/licenses/MIT) 4 * PURPOSE: Test for floating point conversion 5 * COPYRIGHT: Copyright 2024 Timo Kreuzer <timo.kreuzer@reactos.org> 6 */ 7 8 #include <apitest.h> 9 10 /* Note: There are 2 behaviors for float to unsigned integer conversion: 11 * 1. The old behavior, which exists only on x86 and CL versions up to somewhere 12 * between 19.40.33811 and 19.41.33923: 13 * - If a negative float is cast to an unsigned integer, the result is ULONG_MAX 14 * for uint32 and ULLONG_MAX for uint64. 15 * - If a float is cast to an unsigned long and the value is larger than ULONG_MAX, 16 * the result is ULONG_MAX. 17 * 2. The new behavior (all x64 and x86 versions after the ones mentioned above): 18 * - If a negative float is cast to an unsigned integer, the result is the same as 19 first casting to the signed type, then casting to the unsigned type. 20 * - If a float is cast to an unsigned integer and the value is too large for the type, 21 * the result is 0 for uint32 and 0x8000000000000000 for uint64. 22 * In the old version, the float to unsigned conversion was inlined and used _ftoul2 and 23 * a comparison against 0x43e0000000000000 (9223372036854775808.0) to check for overflow. 24 * In the new version, the float to unsigned conversion is done by a call to _ftoul2_legacy, 25 * which checks for overflow by comparing against 0x5f800000 (18446744073709551616.0) and 26 * then forwards the call to either _ftol2 or _ftoul2. 27 */ 28 29 #if defined(_M_IX86) && defined(__VS_PROJECT__) && (_MSC_FULL_VER < 194133923) 30 #define OLD_BEHAVIOR 31 #endif 32 33 #ifdef OLD_BEHAVIOR 34 #define ULONG_OVERFLOW ULONG_MAX 35 #define ULONGLONG_OVERFLOW ULLONG_MAX 36 #else 37 #define ULONG_OVERFLOW 0ul 38 #define ULONGLONG_OVERFLOW 0x8000000000000000ull 39 #endif 40 41 #ifdef __GNUC__ 42 #define todo_gcc todo_ros 43 #else 44 #define todo_gcc 45 #endif 46 47 __declspec(noinline) 48 long cast_float_to_long(float f) 49 { 50 return (long)f; 51 } 52 53 __declspec(noinline) 54 unsigned long cast_float_to_ulong(float f) 55 { 56 return (unsigned long)f; 57 } 58 59 __declspec(noinline) 60 long cast_double_to_long(double d) 61 { 62 return (long)d; 63 } 64 65 __declspec(noinline) 66 unsigned long cast_double_to_ulong(double d) 67 { 68 return (unsigned long)d; 69 } 70 71 __declspec(noinline) 72 long long cast_float_to_longlong(float f) 73 { 74 return (long long)f; 75 } 76 77 __declspec(noinline) 78 unsigned long long cast_float_to_ulonglong(float f) 79 { 80 return (unsigned long long)f; 81 } 82 83 __declspec(noinline) 84 long long cast_double_to_longlong(double d) 85 { 86 return (long long)d; 87 } 88 89 __declspec(noinline) 90 unsigned long long cast_double_to_ulonglong(double d) 91 { 92 return (unsigned long long)d; 93 } 94 95 void Test_float(void) 96 { 97 // float to long cast 98 ok_eq_long(cast_float_to_long(0.0f), 0l); 99 ok_eq_long(cast_float_to_long(1.0f), 1l); 100 ok_eq_long(cast_float_to_long(-1.0f), -1l); 101 ok_eq_long(cast_float_to_long(0.5f), 0l); 102 ok_eq_long(cast_float_to_long(-0.5f), 0l); 103 ok_eq_long(cast_float_to_long(0.999999f), 0l); 104 ok_eq_long(cast_float_to_long(-0.999999f), 0l); 105 ok_eq_long(cast_float_to_long(2147483500.0f), 2147483520l); 106 ok_eq_long(cast_float_to_long(2147483583.999f), 2147483520l); 107 ok_eq_long(cast_float_to_long(-2147483583.999f), -2147483520l); 108 ok_eq_long(cast_float_to_long(2147483584.0f), LONG_MIN); // -2147483648 109 ok_eq_long(cast_float_to_long(2147483648.0f), LONG_MIN); // -2147483648 110 ok_eq_long(cast_float_to_long(-2147483648.0f), LONG_MIN); // -2147483648 111 ok_eq_long(cast_float_to_long(10000000000.0f), LONG_MIN); 112 ok_eq_long(cast_float_to_long(-10000000000.0f), LONG_MIN); 113 114 // float to unsigned long cast (positive values) 115 ok_eq_ulong(cast_float_to_ulong(0.0f), 0ul); 116 ok_eq_ulong(cast_float_to_ulong(1.0f), 1ul); 117 ok_eq_ulong(cast_float_to_ulong(0.5f), 0ul); 118 ok_eq_ulong(cast_float_to_ulong(0.999999f), 0ul); 119 ok_eq_ulong(cast_float_to_ulong(2147483648.0f), 2147483648ul); // 0x80000000 120 ok_eq_ulong(cast_float_to_ulong(4294967150.0f), 4294967040ul); // 0xFFFFFF00 121 ok_eq_ulong(cast_float_to_ulong(4294967294.0f), ULONG_OVERFLOW); 122 123 // float to unsigned long cast (negative values) 124 ok_eq_ulong(cast_float_to_ulong(-0.0f), 0ul); 125 ok_eq_ulong(cast_float_to_ulong(-0.5f), 0ul); 126 ok_eq_ulong(cast_float_to_ulong(-1.0f), ULONG_MAX); 127 #ifdef OLD_BEHAVIOR 128 ok_eq_ulong(cast_float_to_ulong(-10.0f), ULONG_MAX); 129 ok_eq_ulong(cast_float_to_ulong(-1147483648.0f), ULONG_MAX); 130 ok_eq_ulong(cast_float_to_ulong(-2147483648.0f), ULONG_MAX); 131 #else 132 ok_eq_ulong(cast_float_to_ulong(-10.0f), (unsigned long)-10); 133 ok_eq_ulong(cast_float_to_ulong(-1147483648.0f), (unsigned long)-1147483648ll); 134 ok_eq_ulong(cast_float_to_ulong(-2147483648.0f), (unsigned long)-2147483648ll); 135 #endif 136 137 // float to long long cast 138 ok_eq_longlong(cast_float_to_longlong(0.0f), 0ll); 139 ok_eq_longlong(cast_float_to_longlong(1.0f), 1ll); 140 ok_eq_longlong(cast_float_to_longlong(-1.0f), -1ll); 141 ok_eq_longlong(cast_float_to_longlong(0.5f), 0ll); 142 ok_eq_longlong(cast_float_to_longlong(-0.5f), 0ll); 143 ok_eq_longlong(cast_float_to_longlong(0.999999f), 0ll); 144 ok_eq_longlong(cast_float_to_longlong(-0.999999f), 0ll); 145 ok_eq_longlong(cast_float_to_longlong(9223371761976868863.9999f), 9223371487098961920ll); 146 ok_eq_longlong(cast_float_to_longlong(9223371761976868864.0f), LLONG_MIN); 147 ok_eq_longlong(cast_float_to_longlong(-9223371761976868863.9999f), -9223371487098961920ll); 148 ok_eq_longlong(cast_float_to_longlong(-9223371761976868864.0f), LLONG_MIN); 149 ok_eq_longlong(cast_float_to_longlong(100000000000000000000.0f), LLONG_MIN); 150 ok_eq_longlong(cast_float_to_longlong(-100000000000000000000.0f), LLONG_MIN); 151 152 // float to unsigned long long cast (positive values) 153 ok_eq_ulonglong(cast_float_to_ulonglong(0.0f), 0ull); 154 ok_eq_ulonglong(cast_float_to_ulonglong(1.0f), 1ull); 155 ok_eq_ulonglong(cast_float_to_ulonglong(0.5f), 0ull); 156 ok_eq_ulonglong(cast_float_to_ulonglong(0.999999f), 0ull); 157 ok_eq_ulonglong(cast_float_to_ulonglong(9223371487098961920.0f), 9223371487098961920ull); // 0x7FFFFF8000000000 158 ok_eq_ulonglong(cast_float_to_ulonglong(9223372036854775808.0f), 9223372036854775808ull); // 0x8000000000000000 159 ok_eq_ulonglong(cast_float_to_ulonglong(18446743523953737727.9f), 18446742974197923840ull); // 0xFFFFFF0000000000 160 todo_gcc ok_eq_ulonglong(cast_float_to_ulonglong(18446743523953737728.0f), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF 161 todo_gcc ok_eq_ulonglong(cast_float_to_ulonglong(20000000000000000000.0f), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF 162 163 // float to unsigned long long cast (negative values) 164 ok_eq_ulonglong(cast_float_to_ulonglong(-0.0f), 0ull); 165 ok_eq_ulonglong(cast_float_to_ulonglong(-0.5f), 0ull); 166 ok_eq_ulonglong(cast_float_to_ulonglong(-1.0f), 18446744073709551615ull); 167 #ifdef OLD_BEHAVIOR 168 ok_eq_ulonglong(cast_float_to_ulonglong(-10.0f), ULLONG_MAX); 169 ok_eq_ulonglong(cast_float_to_ulonglong(-1147483648.0f), ULLONG_MAX); 170 ok_eq_ulonglong(cast_float_to_ulonglong(-2147483648.0f), ULLONG_MAX); 171 ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868863.9f), ULLONG_MAX); 172 ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868864.0f), ULLONG_MAX); 173 ok_eq_ulonglong(cast_float_to_ulonglong(-9223372036854775808.0f), ULLONG_MAX); 174 #else 175 ok_eq_ulonglong(cast_float_to_ulonglong(-10.0f), (unsigned long long)-10); 176 ok_eq_ulonglong(cast_float_to_ulonglong(-1147483648.0f), (unsigned long long)-1147483648ll); 177 ok_eq_ulonglong(cast_float_to_ulonglong(-2147483648.0f), (unsigned long long)-2147483648ll); 178 ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868863.9f), (unsigned long long)-9223371487098961920); 179 ok_eq_ulonglong(cast_float_to_ulonglong(-9223371761976868864.0f), (unsigned long long)(-9223372036854775807ll - 1)); // 0x8000000000000000 / ULONGLONG_OVERFLOW 180 ok_eq_ulonglong(cast_float_to_ulonglong(-9223372036854775808.0f), (unsigned long long)(-9223372036854775807ll - 1)); // 0x8000000000000000 / ULONGLONG_OVERFLOW 181 #endif 182 ok_eq_ulonglong(cast_float_to_ulonglong(-100000000000000000000.0f), ULONGLONG_OVERFLOW); 183 } 184 185 void Test_double(void) 186 { 187 // double to long cast 188 ok_eq_long(cast_double_to_long(0.0), 0l); 189 ok_eq_long(cast_double_to_long(1.0), 1l); 190 ok_eq_long(cast_double_to_long(-1.0), -1l); 191 ok_eq_long(cast_double_to_long(0.5), 0l); 192 ok_eq_long(cast_double_to_long(-0.5), 0l); 193 ok_eq_long(cast_double_to_long(0.999999999), 0l); 194 ok_eq_long(cast_double_to_long(-0.999999999), 0l); 195 ok_eq_long(cast_double_to_long(2147483647.99999), 2147483647l); 196 ok_eq_long(cast_double_to_long(-2147483647.99999), -2147483647l); 197 ok_eq_long(cast_double_to_long(2147483648.0), LONG_MIN); // -2147483648 198 ok_eq_long(cast_double_to_long(-2147483648.0), LONG_MIN); // -2147483648 199 ok_eq_long(cast_double_to_long(10000000000.0), LONG_MIN); 200 ok_eq_long(cast_double_to_long(-10000000000.0), LONG_MIN); 201 202 // double to unsigned long cast (positive values) 203 ok_eq_ulong(cast_double_to_ulong(0.0), 0ul); 204 ok_eq_ulong(cast_double_to_ulong(1.0), 1ul); 205 ok_eq_ulong(cast_double_to_ulong(0.5), 0ul); 206 ok_eq_ulong(cast_double_to_ulong(0.999999999), 0ul); 207 ok_eq_ulong(cast_double_to_ulong(2147483648.0), 2147483648ul); // 0x80000000 208 ok_eq_ulong(cast_double_to_ulong(4294967295.0), 4294967295ul); // 0xFFFFFFFF 209 ok_eq_ulong(cast_double_to_ulong(4294967296.0), ULONG_OVERFLOW); 210 211 // double to unsigned long cast (negative values) 212 ok_eq_ulong(cast_double_to_ulong(-0.0), 0ul); 213 ok_eq_ulong(cast_double_to_ulong(-0.5), 0ul); 214 ok_eq_ulong(cast_double_to_ulong(-1.0), ULONG_MAX); 215 #ifdef OLD_BEHAVIOR 216 ok_eq_ulong(cast_double_to_ulong(-10.0), ULONG_MAX); 217 ok_eq_ulong(cast_double_to_ulong(-1147483648.0), ULONG_MAX); 218 ok_eq_ulong(cast_double_to_ulong(-2147483648.0), ULONG_MAX); 219 #else 220 ok_eq_ulong(cast_double_to_ulong(-10.0), (unsigned long)-10); 221 ok_eq_ulong(cast_double_to_ulong(-1147483648.0), (unsigned long)-1147483648ll); 222 ok_eq_ulong(cast_double_to_ulong(-2147483648.0), (unsigned long)-2147483648ll); 223 #endif 224 225 // double to long long cast 226 ok_eq_longlong(cast_double_to_longlong(0.0), 0ll); 227 ok_eq_longlong(cast_double_to_longlong(1.0), 1ll); 228 ok_eq_longlong(cast_double_to_longlong(-1.0), -1ll); 229 ok_eq_longlong(cast_double_to_longlong(0.5), 0ll); 230 ok_eq_longlong(cast_double_to_longlong(-0.5), 0ll); 231 ok_eq_longlong(cast_double_to_longlong(0.999999), 0ll); 232 ok_eq_longlong(cast_double_to_longlong(-0.999999), 0ll); 233 ok_eq_longlong(cast_double_to_longlong(9223372036854775295.9), 9223372036854774784ll); 234 ok_eq_longlong(cast_double_to_longlong(9223372036854775296.0), LLONG_MIN); 235 ok_eq_longlong(cast_double_to_longlong(-9223372036854775295.9), -9223372036854774784ll); 236 ok_eq_longlong(cast_double_to_longlong(-9223372036854775296.0), LLONG_MIN); 237 ok_eq_longlong(cast_double_to_longlong(100000000000000000000.0), LLONG_MIN); 238 ok_eq_longlong(cast_double_to_longlong(-100000000000000000000.0), LLONG_MIN); 239 240 // double to unsigned long long cast (positive values) 241 ok_eq_ulonglong(cast_double_to_ulonglong(0.0), 0ull); 242 ok_eq_ulonglong(cast_double_to_ulonglong(1.0), 1ull); 243 ok_eq_ulonglong(cast_double_to_ulonglong(0.5), 0ull); 244 ok_eq_ulonglong(cast_double_to_ulonglong(0.999999), 0ull); 245 ok_eq_ulonglong(cast_double_to_ulonglong(9223372036854774784.0), 9223372036854774784ull); // 0x7FFFFFFFFFFFFC00 246 ok_eq_ulonglong(cast_double_to_ulonglong(9223372036854775808.0), 9223372036854775808ull); // 0x8000000000000000 247 ok_eq_ulonglong(cast_double_to_ulonglong(18446744073709550591.9), 18446744073709549568ull); // 0xFFFFFFFFFFFFF800 248 todo_gcc ok_eq_ulonglong(cast_double_to_ulonglong(18446744073709550592.0), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF 249 todo_gcc ok_eq_ulonglong(cast_double_to_ulonglong(18446744073709551616.0), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF 250 todo_gcc ok_eq_ulonglong(cast_double_to_ulonglong(20000000000000000000.0), ULONGLONG_OVERFLOW); // 0x8000000000000000 / 0xFFFFFFFFFFFFFFFF 251 252 // float to unsigned long long cast (negative values) 253 ok_eq_ulonglong(cast_double_to_ulonglong(-0.0), 0ull); 254 ok_eq_ulonglong(cast_double_to_ulonglong(-0.5), 0ull); 255 ok_eq_ulonglong(cast_double_to_ulonglong(-1.0), 18446744073709551615ull); 256 #ifdef OLD_BEHAVIOR 257 ok_eq_ulonglong(cast_double_to_ulonglong(-10.0), ULLONG_MAX); 258 ok_eq_ulonglong(cast_double_to_ulonglong(-1147483648.0), ULLONG_MAX); 259 ok_eq_ulonglong(cast_double_to_ulonglong(-2147483648.0), ULLONG_MAX); 260 ok_eq_ulonglong(cast_double_to_ulonglong(-9223371761976868863.9), ULLONG_MAX); 261 ok_eq_ulonglong(cast_double_to_ulonglong(-9223371761976868864.0), ULLONG_MAX); 262 ok_eq_ulonglong(cast_double_to_ulonglong(-9223372036854775808.0), ULLONG_MAX); 263 #else 264 ok_eq_ulonglong(cast_double_to_ulonglong(-10.0), (unsigned long long)-10); 265 ok_eq_ulonglong(cast_double_to_ulonglong(-1147483648.0), (unsigned long long)-1147483648ll); 266 ok_eq_ulonglong(cast_double_to_ulonglong(-2147483648.0), (unsigned long long)-2147483648ll); 267 ok_eq_ulonglong(cast_double_to_ulonglong(-9223372036854775000.0), (unsigned long long)-9223372036854774784ll); 268 ok_eq_ulonglong(cast_double_to_ulonglong(-9223372036854775808.0), (unsigned long long)(-9223372036854775807ll - 1)); 269 #endif 270 ok_eq_ulonglong(cast_double_to_ulonglong(-100000000000000000000.0), ULONGLONG_OVERFLOW); 271 } 272 273 START_TEST(floatconv) 274 { 275 Test_float(); 276 Test_double(); 277 } 278