Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : /*!
12 : * \file kernel_fp16.cpp
13 : * \brief
14 : */
15 : #include "kernel_fp16.h"
16 :
17 : namespace {
18 : constexpr uint16_t K_MAN_BIT_LENGTH = 11;
19 : constexpr int16_t HFEXP_NUM = 31;
20 : constexpr uint32_t ERET_NUM = 255;
21 : } // namespace
22 :
23 : // namespace float16 {
24 : /**
25 : * @ingroup half global filed
26 : * @brief round mode of last valid digital
27 : */
28 : const enum TagFp16RoundMode ROUND_MODE = TagFp16RoundMode::K_ROUND_TO_NEAREST;
29 :
30 36 : void ExtractFp16(const uint16_t& val, uint16_t& s, int16_t& e, uint16_t& m)
31 : {
32 : // 1.Extract
33 36 : s = FP16_EXTRAC_SIGN(val);
34 36 : e = FP16_EXTRAC_EXP(val);
35 36 : m = FP16_EXTRAC_MAN(val);
36 : // Denormal
37 36 : if (e == 0) {
38 4 : e = 1;
39 : }
40 36 : }
41 :
42 : /**
43 : * @ingroup half static method
44 : * @param [in] man truncated mantissa
45 : * @param [in] shiftOut left shift bits based on ten bits
46 : * @brief judge whether to add one to the result while converting half to
47 : * other datatype
48 : * @return Return true if add one, otherwise false
49 : */
50 38 : static bool IsRoundOne(uint64_t man, uint16_t truncLen)
51 : {
52 38 : uint64_t mask0 = 0x4;
53 38 : uint64_t mask1 = 0x2;
54 : uint64_t mask2;
55 38 : uint16_t shiftOut = static_cast<uint16_t>(truncLen - static_cast<uint16_t>(DimIndex::K_DIM2));
56 38 : mask0 = mask0 << shiftOut;
57 38 : mask1 = mask1 << shiftOut;
58 38 : mask2 = mask1 - 1;
59 :
60 38 : bool lastBit = ((man & mask0) > 0);
61 38 : bool truncHigh = false;
62 38 : bool truncLeft = false;
63 : if (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) {
64 38 : truncHigh = ((man & mask1) > 0);
65 38 : truncLeft = ((man & mask2) > 0);
66 : }
67 38 : return (truncHigh && (truncLeft || lastBit));
68 : }
69 :
70 : /**
71 : * @ingroup half public method
72 : * @param [in] exp exponent of half value
73 : * @param [in] man exponent of half value
74 : * @brief normalize half value
75 : * @return
76 : */
77 24 : static void Fp16Normalize(int16_t& exp, uint16_t& man)
78 : {
79 : // set to invalid data
80 24 : if (exp >= static_cast<int16_t>(Fp16BasicParam::K_FP16_MAX_EXP)) {
81 2 : exp = static_cast<int16_t>(Fp16BasicParam::K_FP16_MAX_EXP);
82 2 : man = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_MAN);
83 22 : } else if ((exp == 0) && (man == static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT))) {
84 0 : exp++;
85 0 : man = 0;
86 : }
87 24 : }
88 :
89 : /**
90 : * @ingroup half math conversion static method
91 : * @param [in] fpVal uint16_t value of half object
92 : * @brief Convert half to float/fp32
93 : * @return Return float/fp32 value of fpVal which is the value of half object
94 : */
95 18 : static float Fp16ToFloat(const uint16_t& fpVal)
96 : {
97 : uint16_t hfSign;
98 : uint16_t hfMan;
99 : int16_t hfExp;
100 18 : ExtractFp16(fpVal, hfSign, hfExp, hfMan);
101 :
102 18 : while ((hfMan != 0) && ((hfMan & static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT)) == 0)) {
103 0 : hfMan <<= 1;
104 0 : hfExp--;
105 : }
106 :
107 : uint32_t eRet;
108 : uint32_t mRet;
109 18 : uint32_t sRet = hfSign;
110 :
111 18 : if (hfExp == HFEXP_NUM) {
112 2 : eRet = ERET_NUM;
113 2 : mRet = hfMan
114 2 : << (static_cast<uint32_t>(Fp32BasicParam::K_FP32_MAN_LEN) -
115 : static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN));
116 2 : uint32_t fVal = FP32_CONSTRUCTOR(sRet, eRet, mRet);
117 2 : auto pRetV = reinterpret_cast<float*>(&fVal);
118 :
119 2 : return *pRetV;
120 : }
121 :
122 16 : if (hfMan == 0) {
123 4 : eRet = 0;
124 4 : mRet = 0;
125 : } else {
126 12 : eRet = (static_cast<uint32_t>(hfExp) - static_cast<uint32_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) +
127 : static_cast<uint32_t>(Fp32BasicParam::K_FP32_EXP_BIAS);
128 12 : mRet = static_cast<uint32_t>(hfMan & static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_MASK));
129 12 : mRet = mRet
130 : << (static_cast<uint32_t>(Fp32BasicParam::K_FP32_MAN_LEN) -
131 : static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN));
132 : }
133 16 : uint32_t fVal = FP32_CONSTRUCTOR(sRet, eRet, mRet);
134 16 : auto pRetV = reinterpret_cast<float*>(&fVal);
135 :
136 16 : return *pRetV;
137 : }
138 :
139 : /**
140 : * @ingroup half math conversion static method
141 : * @param [in] fpVal uint16_t value of half object
142 : * @brief Convert half to double/fp64
143 : * @return Return double/fp64 value of fpVal which is the value of half object
144 : */
145 2 : static double Fp16ToDouble(const uint16_t& fpVal)
146 : {
147 : uint16_t hfSign;
148 : uint16_t hfMan;
149 : int16_t hfExp;
150 2 : ExtractFp16(fpVal, hfSign, hfExp, hfMan);
151 :
152 2 : while ((hfMan != 0) && ((hfMan & static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT)) == 0)) {
153 0 : hfMan <<= 1;
154 0 : hfExp--;
155 : }
156 :
157 : uint64_t eRet;
158 : uint64_t mRet;
159 2 : if (hfMan == 0) {
160 0 : eRet = 0;
161 0 : mRet = 0;
162 : } else {
163 2 : eRet = (static_cast<uint64_t>(hfExp) - static_cast<uint64_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) +
164 : static_cast<uint64_t>(Fp64BasicParam::K_FP64_EXP_BIAS);
165 2 : mRet = hfMan & static_cast<uint64_t>(Fp16BasicParam::K_FP16_MAN_MASK);
166 2 : mRet = mRet
167 : << (static_cast<uint64_t>(Fp64BasicParam::K_FP64_MAN_LEN) -
168 : static_cast<uint64_t>(Fp16BasicParam::K_FP16_MAN_LEN));
169 : }
170 2 : uint64_t fVal = (static_cast<uint64_t>(hfSign) << static_cast<uint64_t>(Fp64BasicParam::K_FP64_SIGN_INDEX)) |
171 2 : (eRet << static_cast<uint64_t>(Fp64BasicParam::K_FP64_MAN_LEN)) | (mRet);
172 2 : auto pRetV = reinterpret_cast<double*>(&fVal);
173 :
174 2 : return *pRetV;
175 : }
176 :
177 : // / @ingroup half static method
178 : // / @param [in] sRet sign of half value
179 : // / @param [in] longIntM man uint64_t value of half object
180 : // / @param [in] shiftOut shift offset
181 : // / @brief calculate uint8 value by sign,man and shift offset
182 : // / @return Return uint8 value of half object
183 0 : static uint8_t GetUint8ValByMan(uint8_t sRet, const uint64_t& longIntM, const uint16_t& shiftOut)
184 : {
185 0 : bool needRound = IsRoundOne(longIntM, shiftOut + static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN));
186 0 : auto mRet = static_cast<uint8_t>(
187 0 : (longIntM >> (static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN) + static_cast<uint32_t>(shiftOut))) &
188 : static_cast<uint8_t>(NumBitMax::K_BIT_LEN8_MAX));
189 0 : needRound = needRound && (((sRet == 0) && (mRet < static_cast<uint8_t>(NumBitMax::K_INT8_MAX))) ||
190 0 : ((sRet == 1) && (mRet <= static_cast<uint8_t>(NumBitMax::K_INT8_MAX))));
191 0 : if (needRound) {
192 0 : mRet++;
193 : }
194 0 : if (sRet != 0) {
195 0 : mRet = (~mRet) + 1;
196 : }
197 0 : if (mRet == 0) {
198 0 : sRet = 0;
199 : }
200 0 : return static_cast<uint8_t>((sRet << static_cast<uint16_t>(BitShift::K_BIT_SHIFT7)) | (mRet));
201 : }
202 :
203 2 : static void CalcOverflowFlagInt8(
204 : const uint8_t& sRet, uint16_t& hfE, uint64_t& longIntM, uint8_t& overflowFlag, uint16_t& shiftOut)
205 : {
206 14 : while (hfE != static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
207 14 : if (hfE > static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
208 14 : hfE--;
209 14 : longIntM = longIntM << 1;
210 14 : if ((sRet == 1) && (longIntM >= 0x20000u)) { // sign=1,negative number(<0)
211 0 : longIntM = 0x20000u; // 10 0000 0000 0000 0000 10(half-man)+7(int8)=17bit
212 0 : overflowFlag = 1;
213 0 : break;
214 14 : } else if ((sRet != 1) && (longIntM >= 0x1FFFFu)) { // sign=0,positive number(>0)
215 2 : longIntM = 0x1FFFFu; // 01 1111 1111 1111 1111 10(half-man)+7(int8)
216 2 : overflowFlag = 1;
217 2 : break;
218 : }
219 : } else {
220 0 : hfE++;
221 0 : shiftOut++;
222 : }
223 : }
224 2 : }
225 :
226 : /**
227 : * @ingroup half math conversion static method
228 : * @param [in] fpVal uint16_t value of half object
229 : * @brief Convert half to int8_t
230 : * @return Return int8_t value of fpVal which is the value of half object
231 : */
232 2 : static int8_t Fp16ToInt8(const uint16_t& fpVal)
233 : {
234 : uint8_t ret;
235 : // 1.get sRet and shift it to bit0.
236 2 : uint8_t sRet = static_cast<uint8_t>(FP16_EXTRAC_SIGN(fpVal));
237 : // 2.get hfE and hfM
238 2 : uint16_t hfE = static_cast<uint16_t>(FP16_EXTRAC_EXP(fpVal));
239 2 : uint16_t hfM = FP16_EXTRAC_MAN(fpVal);
240 :
241 2 : if (FP16_IS_DENORM(fpVal)) { // Denormalized number
242 0 : return 0;
243 : }
244 :
245 2 : uint64_t longIntM = hfM;
246 2 : uint8_t overflowFlag = 0;
247 2 : uint16_t shiftOut = 0;
248 2 : if (FP16_IS_INVALID(fpVal)) { // Inf or NaN
249 0 : overflowFlag = 1;
250 : } else {
251 2 : CalcOverflowFlagInt8(sRet, hfE, longIntM, overflowFlag, shiftOut);
252 : }
253 2 : if (overflowFlag != 0) {
254 2 : ret = static_cast<uint8_t>(NumBitMax::K_INT8_MAX) + sRet;
255 : } else {
256 : // Generate final result
257 0 : ret = GetUint8ValByMan(sRet, longIntM, shiftOut);
258 : }
259 :
260 2 : return static_cast<int8_t>(ret);
261 : }
262 :
263 2 : static void CalcOverflowFlagUInt8(
264 : uint16_t& hfE, uint64_t& longIntM, uint8_t& overflowFlag, uint8_t& mRet, uint16_t& shiftOut)
265 : {
266 16 : while (hfE != static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
267 16 : if (hfE > static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
268 16 : hfE--;
269 16 : longIntM = longIntM << 1;
270 16 : if (longIntM >= 0x40000Lu) { // overflow 0100 0000 0000 0000 0000
271 2 : longIntM = 0x3FFFFLu; // 11 1111 1111 1111 1111 10(half-man)+8(uint8)=18bit
272 2 : overflowFlag = 1;
273 2 : mRet = ~0;
274 2 : break;
275 : }
276 : } else {
277 0 : hfE++;
278 0 : shiftOut++;
279 : }
280 : }
281 2 : }
282 :
283 : /**
284 : * @ingroup half math conversion static method
285 : * @param [in] fpVal uint16_t value of half object
286 : * @brief Convert half to uint8_t
287 : * @return Return uint8_t value of fpVal which is the value of half object
288 : */
289 2 : static uint8_t Fp16ToUInt8(const uint16_t& fpVal)
290 : {
291 2 : uint8_t mRet = 0;
292 : // 1.get sRet and shift it to bit0.
293 2 : uint16_t sRet = FP16_EXTRAC_SIGN(fpVal);
294 : // 2.get hfE and hfM
295 2 : uint16_t hfE = static_cast<uint16_t>(FP16_EXTRAC_EXP(fpVal));
296 2 : uint16_t hfM = FP16_EXTRAC_MAN(fpVal);
297 :
298 2 : if (FP16_IS_DENORM(fpVal)) { // Denormalized number
299 0 : return 0;
300 : }
301 :
302 2 : if (FP16_IS_INVALID(fpVal)) { // Inf or NaN
303 0 : mRet = ~0;
304 : } else {
305 2 : uint64_t longIntM = hfM;
306 2 : uint8_t overflowFlag = 0;
307 2 : uint16_t shiftOut = 0;
308 2 : CalcOverflowFlagUInt8(hfE, longIntM, overflowFlag, mRet, shiftOut);
309 2 : if (overflowFlag == 0) {
310 0 : bool needRound = IsRoundOne(longIntM, shiftOut + static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN));
311 0 : mRet = static_cast<uint8_t>(
312 0 : (longIntM >>
313 0 : (static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN) + static_cast<uint32_t>(shiftOut))) &
314 : static_cast<uint8_t>(NumBitMax::K_BIT_LEN8_MAX));
315 0 : if (needRound && (mRet != static_cast<uint8_t>(NumBitMax::K_BIT_LEN8_MAX))) {
316 0 : mRet++;
317 : }
318 : }
319 : }
320 :
321 2 : if (sRet == 1) { // Negative number
322 0 : mRet = 0;
323 : }
324 : // mRet equal to final result
325 2 : return mRet;
326 : }
327 : // / @ingroup half static method
328 : // / @param [in] sRet sign of half value
329 : // / @param [in] longIntM man uint64_t value of half object
330 : // / @param [in] shiftOut shift offset
331 : // / @brief calculate uint16 value by sign,man and shift offset
332 : // / @return Return uint16 value of half object
333 2 : static uint16_t GetUint16ValByMan(uint16_t sRet, const uint64_t& longIntM, const uint16_t& shiftOut)
334 : {
335 2 : bool needRound = IsRoundOne(longIntM, shiftOut + static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN));
336 2 : auto mRet = static_cast<uint16_t>(
337 2 : (longIntM >> (static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN) + static_cast<uint32_t>(shiftOut))) &
338 : static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX));
339 2 : if (needRound && (mRet < static_cast<int16_t>(NumBitMax::K_INT16_MAX))) {
340 0 : mRet++;
341 : }
342 2 : if (sRet != 0) {
343 0 : mRet = (~mRet) + 1;
344 : }
345 2 : if (mRet == 0) {
346 0 : sRet = 0;
347 : }
348 2 : return static_cast<uint16_t>((sRet << static_cast<uint16_t>(BitShift::K_BIT_SHIFT15)) | (mRet));
349 : }
350 :
351 2 : static void CalcOverflowFlagInt16(
352 : uint16_t& hfE, uint64_t& longIntM, const uint16_t& sRet, uint8_t& overflowFlag, uint16_t& shiftOut)
353 : {
354 30 : while (hfE != static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
355 28 : if (hfE > static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
356 28 : longIntM = longIntM << 1;
357 28 : hfE--;
358 28 : if ((sRet == 1) && (longIntM > 0x2000000Lu)) { // sign=1,negative number(<0)
359 0 : longIntM = 0x2000000Lu; // 10(half-man)+15(int16)=25bit
360 0 : overflowFlag = 1;
361 0 : break;
362 28 : } else if ((sRet != 1) && (longIntM >= 0x1FFFFFFLu)) { // sign=0,positive number(>0) Overflow
363 0 : longIntM = 0x1FFFFFFLu; // 10(half-man)+15(int16)=25bit
364 0 : overflowFlag = 1;
365 0 : break;
366 : }
367 : } else {
368 0 : shiftOut++;
369 0 : hfE++;
370 : }
371 : }
372 2 : }
373 : /**
374 : * @ingroup half math conversion static method
375 : * @param [in] fpVal uint16_t value of half object
376 : * @brief Convert half to int16_t
377 : * @return Return int16_t value of fpVal which is the value of half object
378 : */
379 2 : static int16_t Fp16ToInt16(const uint16_t& fpVal)
380 : {
381 : int16_t ret;
382 : uint16_t retV;
383 : // 1.get sRet and shift it to bit0.
384 2 : uint16_t sRet = FP16_EXTRAC_SIGN(fpVal);
385 : // 2.get hfE and hfM
386 2 : uint16_t hfM = FP16_EXTRAC_MAN(fpVal);
387 2 : uint16_t hfE = static_cast<uint16_t>(FP16_EXTRAC_EXP(fpVal));
388 :
389 2 : if (FP16_IS_DENORM(fpVal)) { // Denormalized number
390 0 : retV = 0;
391 0 : ret = *(reinterpret_cast<uint8_t*>(&retV));
392 0 : return ret;
393 : }
394 :
395 2 : uint8_t overflowFlag = 0;
396 2 : uint16_t shiftOut = 0;
397 2 : uint64_t longIntM = hfM;
398 2 : if (FP16_IS_INVALID(fpVal)) { // Inf or NaN
399 0 : overflowFlag = 1;
400 : } else {
401 2 : CalcOverflowFlagInt16(hfE, longIntM, sRet, overflowFlag, shiftOut);
402 : }
403 2 : if (overflowFlag != 0) {
404 0 : retV = static_cast<int16_t>(NumBitMax::K_INT16_MAX) + sRet;
405 : } else {
406 : // Generate final result
407 2 : retV = GetUint16ValByMan(sRet, longIntM, shiftOut);
408 : }
409 2 : ret = *(reinterpret_cast<int16_t*>(&retV));
410 2 : return ret;
411 : }
412 :
413 : /**
414 : * @ingroup half math conversion static method
415 : * @param [in] fpVal uint16_t value of half object
416 : * @brief Convert half to uint16_t
417 : * @return Return uint16_t value of fpVal which is the value of half object
418 : */
419 14 : static uint16_t Fp16ToUInt16(const uint16_t& fpVal)
420 : {
421 : uint16_t mRet;
422 : // 1.get sRet and shift it to bit0.
423 14 : uint16_t sRet = FP16_EXTRAC_SIGN(fpVal);
424 : // 2.get hfE and hfM
425 14 : int16_t hfE = FP16_EXTRAC_EXP(fpVal);
426 14 : uint16_t hfM = FP16_EXTRAC_MAN(fpVal);
427 :
428 14 : if (FP16_IS_DENORM(fpVal)) { // Denormalized number
429 4 : return 0;
430 : }
431 :
432 10 : if (FP16_IS_INVALID(fpVal)) { // Inf or NaN
433 0 : mRet = ~0;
434 : } else {
435 10 : uint16_t shiftOut = 0;
436 10 : uint64_t longIntM = hfM;
437 86 : while (hfE != static_cast<int16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
438 76 : if (hfE > static_cast<int16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
439 76 : hfE--;
440 76 : longIntM = longIntM << 1;
441 : } else {
442 0 : shiftOut++;
443 0 : hfE++;
444 : }
445 : }
446 10 : bool needRound = IsRoundOne(longIntM, shiftOut + static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN));
447 10 : mRet = static_cast<uint16_t>(
448 10 : (longIntM >> (static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN) + static_cast<uint32_t>(shiftOut))) &
449 : static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX));
450 10 : if (needRound && (mRet != static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX))) {
451 0 : mRet++;
452 : }
453 : }
454 :
455 10 : if (sRet == 1) { // Negative number
456 0 : mRet = 0;
457 : }
458 : // mRet equal to final result
459 10 : return mRet;
460 : }
461 :
462 : /**
463 : * @ingroup half math convertion static method
464 : * @param [in] fpVal uint16_t value of half object
465 : * @brief Convert half to int32_t
466 : * @return Return int32_t value of fpVal which is the value of half object
467 : */
468 12 : static int32_t Fp16ToInt32(const uint16_t& fpVal)
469 : {
470 : uint32_t retV;
471 : // 1.get sRet and shift it to bit0.
472 12 : uint32_t sRet = FP16_EXTRAC_SIGN(fpVal);
473 : // 2.get hfE and hfM
474 12 : int16_t hfE = FP16_EXTRAC_EXP(fpVal);
475 12 : uint16_t hfM = FP16_EXTRAC_MAN(fpVal);
476 :
477 12 : if (FP16_IS_INVALID(fpVal)) { // Inf or NaN
478 2 : retV = static_cast<int32_t>(NumBitMax::K_INT32_MAX) + sRet;
479 : } else {
480 10 : uint64_t longIntM = hfM;
481 10 : uint16_t shiftOut = 0;
482 :
483 102 : while (hfE != static_cast<int16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
484 92 : if (hfE > static_cast<int16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
485 92 : longIntM = longIntM << 1;
486 92 : hfE--;
487 : } else {
488 0 : hfE++;
489 0 : shiftOut++;
490 : }
491 : }
492 10 : bool needRound = IsRoundOne(longIntM, shiftOut + static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN));
493 10 : auto mRet = static_cast<uint32_t>(
494 10 : (longIntM >> (static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN) + static_cast<uint32_t>(shiftOut))) &
495 : static_cast<uint32_t>(NumBitMax::K_BIT_LEN32_MAX));
496 10 : if (needRound && (mRet < static_cast<uint32_t>(NumBitMax::K_INT32_MAX))) {
497 2 : mRet++;
498 : }
499 :
500 10 : if (sRet == 1) {
501 0 : mRet = (~mRet) + 1;
502 : }
503 10 : if (mRet == 0) {
504 0 : sRet = 0;
505 : }
506 : // Generate final result
507 10 : retV = (sRet << static_cast<uint16_t>(BitShift::K_BIT_SHIFT31)) | (mRet);
508 : }
509 :
510 12 : return *(reinterpret_cast<int32_t*>(&retV));
511 : }
512 :
513 : /**
514 : * @ingroup half math conversion static method
515 : * @param [in] fpVal uint16_t value of half object
516 : * @brief Convert half to uint32_t
517 : * @return Return uint32_t value of fpVal which is the value of half object
518 : */
519 2 : static uint32_t Fp16ToUInt32(const uint16_t& fpVal)
520 : {
521 : uint32_t mRet;
522 : // 1.get sRet and shift it to bit0.
523 2 : uint32_t sRet = FP16_EXTRAC_SIGN(fpVal);
524 : // 2.get hfE and hfM
525 2 : int16_t hfE = FP16_EXTRAC_EXP(fpVal);
526 2 : uint16_t hfM = FP16_EXTRAC_MAN(fpVal);
527 :
528 2 : if (FP16_IS_DENORM(fpVal)) { // Denormalized number
529 0 : return 0u;
530 : }
531 :
532 2 : if (FP16_IS_INVALID(fpVal)) { // Inf or NaN
533 0 : mRet = ~0u;
534 : } else {
535 2 : uint64_t longIntM = hfM;
536 2 : uint16_t shiftOut = 0;
537 30 : while (hfE != static_cast<int16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
538 28 : if (hfE > static_cast<int16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) {
539 28 : hfE--;
540 28 : longIntM = longIntM << 1;
541 : } else {
542 0 : hfE++;
543 0 : shiftOut++;
544 : }
545 : }
546 2 : bool needRound = IsRoundOne(longIntM, shiftOut + static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN));
547 2 : mRet =
548 : static_cast<uint32_t>(
549 2 : longIntM >> (static_cast<uint32_t>(Fp16BasicParam::K_FP16_MAN_LEN) + static_cast<uint32_t>(shiftOut))) &
550 : static_cast<uint32_t>(NumBitMax::K_BIT_LEN32_MAX);
551 2 : if (needRound && (mRet != static_cast<uint32_t>(NumBitMax::K_BIT_LEN32_MAX))) {
552 0 : mRet++;
553 : }
554 : }
555 :
556 2 : if (sRet == 1) { // Negative number
557 0 : mRet = 0;
558 : }
559 : // mRet equal to final result
560 2 : return mRet;
561 : }
562 0 : static uint16_t Fp16AddCalVal(const uint16_t& sRet, int16_t eRet, uint16_t mRet, uint32_t mTrunc, uint16_t shiftOut)
563 : {
564 0 : uint16_t mMin = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT) << shiftOut;
565 0 : uint16_t mMax = mMin << 1;
566 : // Denormal
567 0 : while ((mRet < mMin) && (eRet > 0)) { // the value of mRet should not be smaller than 2^23
568 0 : mRet = mRet << 1;
569 0 : mRet += (static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK) & mTrunc) >>
570 : static_cast<uint16_t>(Fp32BasicParam::K_FP32_SIGN_INDEX);
571 0 : mTrunc = mTrunc << 1;
572 0 : eRet = eRet - 1;
573 : }
574 0 : while (mRet >= mMax) { // the value of mRet should be smaller than 2^24
575 0 : mTrunc = mTrunc >> 1;
576 0 : mTrunc = mTrunc | (static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK) * (mRet & 1));
577 0 : mRet = mRet >> 1;
578 0 : eRet = eRet + 1;
579 : }
580 :
581 0 : bool bLastBit = ((mRet & 1) > 0);
582 0 : bool bTruncHigh = (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) &&
583 0 : ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) > 0);
584 0 : bool bTruncLeft = (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) &&
585 0 : ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX)) > 0);
586 0 : mRet = ManRoundToNearest(bLastBit, bTruncHigh, bTruncLeft, mRet, shiftOut);
587 0 : while (mRet >= mMax) {
588 0 : mRet = mRet >> 1;
589 0 : eRet = eRet + 1;
590 : }
591 :
592 0 : if ((eRet == 0) && (mRet <= mMax)) {
593 0 : mRet = mRet >> 1;
594 : }
595 0 : Fp16Normalize(eRet, mRet);
596 0 : uint16_t ret = FP16_CONSTRUCTOR(sRet, static_cast<uint16_t>(eRet), mRet);
597 0 : return ret;
598 : }
599 :
600 : /**
601 : * @ingroup half math operator
602 : * @param [in] v1 left operator value of half object
603 : * @param [in] v2 right operator value of half object
604 : * @brief Performing half addition
605 : * @return Return half result of adding this and fp
606 : */
607 0 : static uint16_t Fp16Add(uint16_t v1, uint16_t v2)
608 : {
609 : uint16_t sa;
610 : uint16_t sb;
611 : int16_t ea;
612 : int16_t eb;
613 : uint32_t ma;
614 : uint32_t mb;
615 : uint16_t maTmp;
616 : uint16_t mbTmp;
617 0 : uint16_t shiftOut = 0;
618 : // 1.Extract
619 0 : ExtractFp16(v1, sa, ea, maTmp);
620 0 : ExtractFp16(v2, sb, eb, mbTmp);
621 0 : ma = maTmp;
622 0 : mb = mbTmp;
623 :
624 : uint16_t sum;
625 : uint16_t sRet;
626 0 : if (sa != sb) {
627 0 : ReverseMan(sa > 0, ma);
628 0 : ReverseMan(sb > 0, mb);
629 0 : sum = static_cast<uint16_t>(GetManSum(ea, ma, eb, mb));
630 0 : sRet = (sum & static_cast<uint16_t>(Fp16BasicParam::K_FP16_SIGN_MASK)) >>
631 : static_cast<uint16_t>(Fp16BasicParam::K_FP16_SIGN_INDEX);
632 0 : ReverseMan(sRet > 0, ma);
633 0 : ReverseMan(sRet > 0, mb);
634 : } else {
635 0 : sum = static_cast<uint16_t>(GetManSum(ea, ma, eb, mb));
636 0 : sRet = sa;
637 : }
638 :
639 0 : if (sum == 0) {
640 0 : shiftOut = 3; // shift to left 3 bits
641 0 : ma = ma << shiftOut;
642 0 : mb = mb << shiftOut;
643 : }
644 :
645 0 : uint32_t mTrunc = 0;
646 0 : int16_t eRet = std::max(ea, eb);
647 0 : uint32_t eTmp = static_cast<uint32_t>(std::abs(ea - eb));
648 0 : if (ea > eb) {
649 0 : mTrunc = (mb << (static_cast<uint32_t>(BitShift::K_BIT_SHIFT32) - eTmp));
650 0 : mb = RightShift(mb, eTmp);
651 0 : } else if (ea < eb) {
652 0 : mTrunc = (ma << (static_cast<uint32_t>(BitShift::K_BIT_SHIFT32) - eTmp));
653 0 : ma = RightShift(ma, eTmp);
654 : }
655 : // calculate mantissav
656 0 : auto mRet = static_cast<uint16_t>(ma + mb);
657 0 : return Fp16AddCalVal(sRet, eRet, mRet, mTrunc, shiftOut);
658 : }
659 :
660 : /**
661 : * @ingroup half math operator
662 : * @param [in] v1 left operator value of half object
663 : * @param [in] v2 right operator value of half object
664 : * @brief Performing half subtraction
665 : * @return Return half result of subtraction fp from this
666 : */
667 0 : static uint16_t Fp16Sub(uint16_t v1, uint16_t v2)
668 : {
669 : // Reverse
670 0 : uint16_t tmp = ((~(v2)) & static_cast<uint16_t>(Fp16BasicParam::K_FP16_SIGN_MASK)) |
671 : (v2 & static_cast<uint16_t>(Fp16BasicParam::K_FP16_ABS_MAX));
672 0 : return Fp16Add(v1, tmp);
673 : }
674 : /**
675 : * @ingroup half math operator
676 : * @param [in] v1 left operator value of half object
677 : * @param [in] v2 right operator value of half object
678 : * @brief Performing half multiplication
679 : * @return Return half result of multiplying this and fp
680 : */
681 4 : static uint16_t Fp16Mul(uint16_t v1, uint16_t v2)
682 : {
683 : uint16_t sa;
684 : uint16_t sb;
685 : int16_t ea;
686 : int16_t eb;
687 : uint16_t mRet;
688 : uint16_t maTmp;
689 : uint16_t mbTmp;
690 : // 1.Extract
691 4 : ExtractFp16(v1, sa, ea, maTmp);
692 4 : ExtractFp16(v2, sb, eb, mbTmp);
693 4 : uint32_t ma = maTmp;
694 4 : uint32_t mb = mbTmp;
695 :
696 4 : int16_t eRet =
697 4 : (ea + eb - static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS)) - static_cast<uint16_t>(DimIndex::K_DIM10);
698 4 : uint32_t mulM = ma * mb;
699 4 : uint16_t sRet = sa ^ sb;
700 :
701 4 : uint32_t mMin = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT);
702 4 : uint32_t mMax = mMin << 1;
703 4 : uint32_t mTrunc = 0;
704 : // the value of mRet should not be smaller than 2^23
705 4 : while ((mulM < mMin) && (eRet > 1)) {
706 0 : mulM = mulM << 1;
707 0 : eRet = eRet - 1;
708 : }
709 44 : while ((mulM >= mMax) || (eRet < 1)) {
710 40 : mTrunc = mTrunc >> 1;
711 40 : mTrunc = mTrunc | (static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK) * (mulM & 1));
712 40 : mulM = mulM >> 1;
713 40 : eRet = eRet + 1;
714 : }
715 4 : bool bLastBit = ((mulM & 1) > 0);
716 4 : bool bTruncHigh = (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) &&
717 4 : ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) > 0);
718 4 : bool bTruncLeft = (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) &&
719 4 : ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX)) > 0);
720 4 : mulM = ManRoundToNearest(bLastBit, bTruncHigh, bTruncLeft, mulM);
721 :
722 4 : while ((mulM >= mMax) || (eRet < 0)) {
723 0 : mulM = mulM >> 1;
724 0 : eRet = eRet + 1;
725 : }
726 :
727 4 : if ((eRet == 1) && (mulM < static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT))) {
728 0 : eRet = 0;
729 : }
730 4 : mRet = static_cast<uint16_t>(mulM);
731 :
732 4 : Fp16Normalize(eRet, mRet);
733 :
734 4 : uint16_t ret = FP16_CONSTRUCTOR(sRet, static_cast<uint16_t>(eRet), mRet);
735 4 : return ret;
736 : }
737 :
738 : /**
739 : * @ingroup half math operator divided
740 : * @param [in] v1 left operator value of half object
741 : * @param [in] v2 right operator value of half object
742 : * @brief Performing half division
743 : * @return Return half result of division this by fp
744 : */
745 4 : static uint16_t Fp16Div(uint16_t v1, uint16_t v2)
746 : {
747 : uint16_t ret;
748 4 : if (FP16_IS_ZERO(v2)) { // result is inf
749 : // throw "half division by zero.";
750 : uint16_t sa;
751 : uint16_t sb;
752 : uint16_t sRet;
753 0 : sa = FP16_EXTRAC_SIGN(v1);
754 0 : sb = FP16_EXTRAC_SIGN(v2);
755 0 : sRet = sa ^ sb;
756 0 : ret = FP16_CONSTRUCTOR(sRet, static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP), 0u);
757 4 : } else if (FP16_IS_ZERO(v1)) {
758 0 : ret = 0u;
759 : } else {
760 : uint16_t sa;
761 : uint16_t sb;
762 : int16_t ea;
763 : int16_t eb;
764 : uint16_t maTmp;
765 : uint16_t mbTmp;
766 : // 1.Extract
767 4 : ExtractFp16(v1, sa, ea, maTmp);
768 4 : ExtractFp16(v2, sb, eb, mbTmp);
769 4 : uint64_t ma = maTmp;
770 4 : uint64_t mb = mbTmp;
771 : uint64_t mTmp;
772 4 : if (ea > eb) {
773 4 : mTmp = ma;
774 4 : int16_t tmp = ea - eb;
775 22 : for (int16_t i = 0; i < tmp; i++) {
776 18 : mTmp = mTmp << 1;
777 : }
778 4 : ma = mTmp;
779 0 : } else if (ea < eb) {
780 0 : mTmp = mb;
781 0 : int16_t tmp = eb - ea;
782 0 : for (int16_t i = 0; i < tmp; i++) {
783 0 : mTmp = mTmp << 1;
784 : }
785 0 : mb = mTmp;
786 : }
787 4 : float mDiv = static_cast<float>(ma * 1.0f / mb);
788 4 : half fpDiv(mDiv);
789 4 : ret = fpDiv.val;
790 4 : if (sa != sb) {
791 0 : ret |= static_cast<uint16_t>(Fp16BasicParam::K_FP16_SIGN_MASK);
792 : }
793 : }
794 4 : return ret;
795 : }
796 :
797 : // operate
798 0 : half half::operator+(const half fp) const
799 : {
800 0 : uint16_t retVal = Fp16Add(val, fp.val);
801 : half ret;
802 0 : ret.val = retVal;
803 0 : return ret;
804 : }
805 0 : half half::operator-(const half fp) const
806 : {
807 0 : uint16_t retVal = Fp16Sub(val, fp.val);
808 : half ret;
809 0 : ret.val = retVal;
810 0 : return ret;
811 : }
812 2 : half half::operator*(const half fp) const
813 : {
814 2 : uint16_t retVal = Fp16Mul(val, fp.val);
815 : half ret;
816 2 : ret.val = retVal;
817 2 : return ret;
818 : }
819 2 : half half::operator/(const half fp) const
820 : {
821 2 : uint16_t retVal = Fp16Div(val, fp.val);
822 : half ret;
823 2 : ret.val = retVal;
824 2 : return ret;
825 : }
826 :
827 0 : half half::operator+=(const half fp)
828 : {
829 0 : val = Fp16Add(val, fp.val);
830 0 : return *this;
831 : }
832 0 : half half::operator-=(const half fp)
833 : {
834 0 : val = Fp16Sub(val, fp.val);
835 0 : return *this;
836 : }
837 2 : half half::operator*=(const half fp)
838 : {
839 2 : val = Fp16Mul(val, fp.val);
840 2 : return *this;
841 : }
842 2 : half half::operator/=(const half fp)
843 : {
844 2 : val = Fp16Div(val, fp.val);
845 2 : return *this;
846 : }
847 :
848 : // compare
849 0 : bool half::operator==(const half& fp) const
850 : {
851 0 : bool result = true;
852 0 : if (FP16_IS_ZERO(val) && FP16_IS_ZERO(fp.val)) {
853 0 : result = true;
854 : } else {
855 0 : result =
856 0 : ((val & static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX)) ==
857 0 : (fp.val & static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX))); // bit compare
858 : }
859 0 : return result;
860 : }
861 0 : bool half::operator!=(const half& fp) const
862 : {
863 0 : bool result = true;
864 0 : if (FP16_IS_ZERO(val) && FP16_IS_ZERO(fp.val)) {
865 0 : result = false;
866 : } else {
867 0 : result =
868 0 : ((val & static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX)) !=
869 0 : (fp.val & static_cast<uint16_t>(NumBitMax::K_BIT_LEN16_MAX))); // bit compare
870 : }
871 0 : return result;
872 : }
873 0 : static bool CmpPosNums(const uint16_t& ea, const uint16_t& eb, const uint16_t& ma, const uint16_t& mb)
874 : {
875 0 : bool result = true;
876 0 : if (ea > eb) { // ea - eb >= 1; Va always larger than Vb
877 0 : result = true;
878 0 : } else if (ea == eb) {
879 0 : result = ma > mb;
880 : } else {
881 0 : result = false;
882 : }
883 0 : return result;
884 : }
885 0 : static bool CmpNegNums(const uint16_t& ea, const uint16_t& eb, const uint16_t& ma, const uint16_t& mb)
886 : {
887 0 : bool result = true;
888 0 : if (ea < eb) {
889 0 : result = true;
890 0 : } else if (ea == eb) {
891 0 : result = ma < mb;
892 : } else {
893 0 : result = false;
894 : }
895 0 : return result;
896 : }
897 0 : bool half::operator>(const half& fp) const
898 : {
899 : uint16_t sa;
900 : uint16_t sb;
901 : uint16_t ea;
902 : uint16_t eb;
903 : uint16_t ma;
904 : uint16_t mb;
905 0 : bool result = true;
906 :
907 : // 1.Extract
908 0 : sa = FP16_EXTRAC_SIGN(val);
909 0 : sb = FP16_EXTRAC_SIGN(fp.val);
910 0 : ea = static_cast<uint16_t>(FP16_EXTRAC_EXP(val));
911 0 : eb = static_cast<uint16_t>(FP16_EXTRAC_EXP(fp.val));
912 0 : ma = FP16_EXTRAC_MAN(val);
913 0 : mb = FP16_EXTRAC_MAN(fp.val);
914 :
915 : // Compare
916 0 : if ((sa == 0) && (sb > 0)) { // + -
917 : // -0=0
918 0 : result = !(FP16_IS_ZERO(val) && FP16_IS_ZERO(fp.val));
919 0 : } else if ((sa == 0) && (sb == 0)) { // + +
920 0 : result = CmpPosNums(ea, eb, ma, mb);
921 0 : } else if ((sa > 0) && (sb > 0)) { // - - opposite to + +
922 0 : result = CmpNegNums(ea, eb, ma, mb);
923 : } else {
924 : // - +
925 0 : result = false;
926 : }
927 :
928 0 : return result;
929 : }
930 :
931 0 : bool half::operator>=(const half& fp) const
932 : {
933 0 : bool result = true;
934 0 : if (((*this) > fp) || ((*this) == fp)) {
935 0 : result = true;
936 : } else {
937 0 : result = false;
938 : }
939 :
940 0 : return result;
941 : }
942 :
943 0 : bool half::operator<=(const half& fp) const
944 : {
945 0 : bool result = true;
946 0 : if ((*this) > fp) {
947 0 : result = false;
948 : }
949 0 : return result;
950 : }
951 :
952 0 : bool half::operator<(const half& fp) const
953 : {
954 0 : bool result = true;
955 0 : if ((*this) >= fp) {
956 0 : result = false;
957 : }
958 0 : return result;
959 : }
960 :
961 0 : half half::operator++()
962 : {
963 0 : half one = 1.0;
964 0 : val = Fp16Add(val, one.val);
965 0 : return *this;
966 : }
967 :
968 0 : half half::operator++(int)
969 : {
970 0 : half oldBf = *this;
971 0 : operator++();
972 0 : return oldBf;
973 : }
974 :
975 0 : half half::operator--()
976 : {
977 0 : half one = 1.0;
978 0 : val = Fp16Sub(val, one.val);
979 0 : return *this;
980 : }
981 :
982 0 : half half::operator--(int)
983 : {
984 0 : half oldBf = *this;
985 0 : operator--();
986 0 : return oldBf;
987 : }
988 :
989 0 : bool half::operator&&(const half fp) const { return (val != 0) && (fp.val != 0); }
990 :
991 0 : bool half::operator||(const half fp) const { return (val != 0) || (fp.val != 0); }
992 :
993 16 : uint16_t half::FloatToFp16(const float& fVal) const
994 : {
995 : uint16_t sRet;
996 : uint16_t mRet;
997 : int16_t eRet;
998 : uint32_t ef;
999 : uint32_t mf;
1000 16 : const uint32_t ui32V = *(reinterpret_cast<const uint32_t*>(&fVal)); // 1:8:23bit sign:exp:man
1001 : uint32_t mLenDelta;
1002 :
1003 16 : sRet = static_cast<uint16_t>(
1004 16 : (ui32V & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) >>
1005 : static_cast<uint16_t>(Fp32BasicParam::K_FP32_SIGN_INDEX)); // 4Byte->2Byte
1006 16 : ef = (ui32V & static_cast<uint32_t>(Fp32BasicParam::K_FP32_EXP_MASK)) >>
1007 : static_cast<uint16_t>(Fp32BasicParam::K_FP32_MAN_LEN); // 8 bit exponent
1008 16 : mf =
1009 : (ui32V &
1010 : static_cast<uint32_t>(Fp32BasicParam::K_FP32_MAN_MASK)); // 23 bit mantissa dont't need to care about denormal
1011 16 : mLenDelta =
1012 : static_cast<uint16_t>(Fp32BasicParam::K_FP32_MAN_LEN) - static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1013 :
1014 16 : bool needRound = false;
1015 : // Exponent overflow/NaN converts to signed inf/NaN
1016 16 : if (ef > 0x8Fu) { // 0x8Fu:142=127+15
1017 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP) - 1;
1018 0 : mRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_MAN);
1019 16 : } else if (ef <= 0x70u) { // 0x70u:112=127-15 Exponent underflow converts to denormalized half or signed zero
1020 4 : eRet = 0;
1021 4 : if (ef >= 0x67) { // 0x67:103=127-24 Denormal
1022 0 : mf = (mf | static_cast<uint32_t>(Fp32BasicParam::K_FP32_MAN_HIDE_BIT));
1023 0 : uint16_t shiftOut = static_cast<uint16_t>(Fp32BasicParam::K_FP32_MAN_LEN);
1024 0 : uint64_t mTmp = (static_cast<uint64_t>(mf)) << (ef - 0x67);
1025 :
1026 0 : needRound = IsRoundOne(mTmp, shiftOut);
1027 0 : mRet = static_cast<uint16_t>(mTmp >> shiftOut);
1028 0 : if (needRound) {
1029 0 : mRet++;
1030 : }
1031 4 : } else if ((ef == 0x66) && (mf > 0)) { // 0x66:102 Denormal 0<f_v<min(Denormal)
1032 0 : mRet = 1;
1033 : } else {
1034 4 : mRet = 0;
1035 : }
1036 : } else { // Regular case with no overflow or underflow
1037 12 : eRet = static_cast<int16_t>(ef - 0x70u);
1038 :
1039 12 : needRound = IsRoundOne(mf, static_cast<uint16_t>(mLenDelta));
1040 12 : mRet = static_cast<uint16_t>(mf >> mLenDelta);
1041 12 : if (needRound) {
1042 2 : mRet++;
1043 : }
1044 12 : if ((mRet & static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT)) != 0) {
1045 0 : eRet++;
1046 : }
1047 : }
1048 :
1049 16 : Fp16Normalize(eRet, mRet);
1050 16 : return FP16_CONSTRUCTOR(sRet, static_cast<uint16_t>(eRet), mRet);
1051 : }
1052 :
1053 4 : uint16_t half::DoubleToFp16(const double& dVal)
1054 : {
1055 : uint16_t sRet;
1056 : uint16_t mRet;
1057 : int16_t eRet;
1058 : uint64_t ed;
1059 : uint64_t md;
1060 4 : uint64_t ui64V = *(reinterpret_cast<const uint64_t*>(&dVal)); // 1:11:52bit sign:exp:man
1061 : uint16_t mLenDelta;
1062 :
1063 4 : sRet = static_cast<uint16_t>(
1064 4 : (ui64V & static_cast<uint64_t>(Fp64BasicParam::K_FP64_SIGN_MASK)) >>
1065 : static_cast<uint16_t>(Fp64BasicParam::K_FP64_SIGN_INDEX)); // 4Byte
1066 4 : ed = (ui64V & static_cast<uint64_t>(Fp64BasicParam::K_FP64_EXP_MASK)) >>
1067 : static_cast<uint16_t>(Fp64BasicParam::K_FP64_MAN_LEN); // 10 bit exponent
1068 4 : md = (ui64V & static_cast<uint64_t>(Fp64BasicParam::K_FP64_MAN_MASK)); // 52 bit mantissa
1069 4 : mLenDelta =
1070 : static_cast<uint16_t>(Fp64BasicParam::K_FP64_MAN_LEN) - static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1071 :
1072 4 : bool needRound = false;
1073 : // Exponent overflow/NaN converts to signed inf/NaN
1074 4 : if (ed >= 0x410u) { // 0x410:1040=1023+16
1075 2 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP) - 1;
1076 2 : mRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_MAN);
1077 2 : val = FP16_CONSTRUCTOR(sRet, static_cast<uint16_t>(eRet), mRet);
1078 2 : } else if (ed <= 0x3F0u) { // Exponent underflow converts to denormalized half or signed zero
1079 : // 0x3F0:1008=1023-15
1080 : // Signed zeros, denormalized floats, and floats with small
1081 : // exponents all convert to signed zero half precision.
1082 0 : eRet = 0;
1083 0 : if (ed >= 0x3E7u) { // 0x3E7u:999=1023-24 Denormal
1084 : // Underflows to a denormalized value
1085 0 : md = (static_cast<uint64_t>(Fp64BasicParam::K_FP64_MAN_HIDE_BIT) | md);
1086 0 : uint16_t shiftOut = static_cast<uint16_t>(Fp64BasicParam::K_FP64_MAN_LEN);
1087 0 : uint64_t mTmp = (static_cast<uint64_t>(md)) << (ed - 0x3E7u);
1088 :
1089 0 : needRound = IsRoundOne(mTmp, shiftOut);
1090 0 : mRet = static_cast<uint16_t>(mTmp >> shiftOut);
1091 0 : if (needRound) {
1092 0 : mRet++;
1093 : }
1094 0 : } else if ((ed == 0x3E6u) && (md > 0)) {
1095 0 : mRet = 1;
1096 : } else {
1097 0 : mRet = 0;
1098 : }
1099 : } else { // Regular case with no overflow or underflow
1100 2 : eRet = static_cast<int16_t>(ed - 0x3F0u);
1101 :
1102 2 : needRound = IsRoundOne(md, mLenDelta);
1103 2 : mRet = static_cast<uint16_t>(md >> mLenDelta);
1104 2 : if (needRound) {
1105 2 : mRet++;
1106 : }
1107 2 : if ((static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT) & mRet) != 0) {
1108 0 : eRet++;
1109 : }
1110 : }
1111 :
1112 4 : Fp16Normalize(eRet, mRet);
1113 4 : return FP16_CONSTRUCTOR(sRet, static_cast<uint16_t>(eRet), mRet);
1114 : }
1115 :
1116 0 : uint16_t half::Int8ToFp16(const int8_t& iVal) const
1117 : {
1118 : uint16_t sRet;
1119 : uint16_t eRet;
1120 : uint16_t mRet;
1121 :
1122 0 : sRet = ((static_cast<uint8_t>(iVal)) & 0x80) == 0 ? 0 : 1;
1123 0 : mRet = static_cast<uint16_t>(((static_cast<uint8_t>(iVal)) & static_cast<int8_t>(NumBitMax::K_INT8_MAX)));
1124 :
1125 0 : if (mRet == 0) {
1126 0 : eRet = 0;
1127 : } else {
1128 0 : if (sRet != 0) { // negative number(<0)
1129 0 : mRet = static_cast<uint16_t>(std::abs(iVal)); // complement
1130 : }
1131 :
1132 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1133 0 : while ((mRet & static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT)) == 0) {
1134 0 : eRet = eRet - 1;
1135 0 : mRet = mRet << 1;
1136 : }
1137 0 : eRet = eRet + static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS);
1138 : }
1139 0 : return FP16_CONSTRUCTOR(sRet, eRet, mRet);
1140 : }
1141 :
1142 0 : uint16_t half::UInt8ToFp16(const uint8_t& uiVal) const
1143 : {
1144 : uint16_t sRet;
1145 : uint16_t eRet;
1146 : uint16_t mRet;
1147 0 : sRet = 0;
1148 0 : eRet = 0;
1149 0 : mRet = uiVal;
1150 0 : if (mRet != 0) {
1151 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1152 0 : while ((mRet & static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT)) == 0) {
1153 0 : mRet = mRet << 1;
1154 0 : eRet = eRet - 1;
1155 : }
1156 0 : eRet = eRet + static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS);
1157 : }
1158 0 : return FP16_CONSTRUCTOR(sRet, eRet, mRet);
1159 : }
1160 :
1161 0 : static void SetValByUint16Val(const uint16_t& inputVal, const uint16_t& sign, uint16_t& retVal)
1162 : {
1163 0 : uint32_t mTmp = (inputVal & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX));
1164 0 : uint16_t mMin = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT);
1165 0 : uint16_t mMax = mMin << 1;
1166 0 : uint16_t len = static_cast<uint16_t>(GetManBitLength(mTmp));
1167 0 : if (mTmp != 0) {
1168 : uint16_t eRet;
1169 0 : if (len > static_cast<uint16_t>(DimIndex::K_DIM11)) {
1170 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS) +
1171 : static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1172 0 : uint32_t eTmp = static_cast<uint32_t>(len) - static_cast<uint32_t>(DimIndex::K_DIM11);
1173 0 : uint32_t truncMask = 1;
1174 0 : for (uint32_t i = 1; i < eTmp; i++) {
1175 0 : truncMask = (truncMask << 1) + 1;
1176 : }
1177 0 : uint32_t mTrunc = (mTmp & truncMask) << (static_cast<uint32_t>(BitShift::K_BIT_SHIFT32) - eTmp);
1178 0 : for (uint32_t i = 0; i < eTmp; i++) {
1179 0 : eRet = eRet + 1;
1180 0 : mTmp = (mTmp >> 1);
1181 : }
1182 0 : bool bLastBit = ((mTmp & 1) > 0);
1183 0 : bool bTruncHigh = static_cast<bool>(0);
1184 0 : bool bTruncLeft = static_cast<bool>(0);
1185 : if (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) { // trunc
1186 0 : bTruncHigh = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) > 0);
1187 0 : bTruncLeft = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX)) > 0);
1188 : }
1189 0 : mTmp = ManRoundToNearest(bLastBit, bTruncHigh, bTruncLeft, mTmp);
1190 0 : while (mTmp >= mMax) {
1191 0 : mTmp = mTmp >> 1;
1192 0 : eRet = eRet + 1;
1193 : }
1194 : } else {
1195 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS);
1196 0 : mTmp = mTmp << static_cast<uint32_t>(K_MAN_BIT_LENGTH - len);
1197 0 : eRet = eRet + (len - static_cast<uint16_t>(1));
1198 : }
1199 0 : auto mRet = static_cast<uint16_t>(mTmp);
1200 0 : retVal = FP16_CONSTRUCTOR(sign, eRet, mRet);
1201 : }
1202 0 : }
1203 :
1204 0 : uint16_t half::Int16ToFp16(const int16_t& iVal) const
1205 : {
1206 0 : uint16_t retVal = 0;
1207 0 : if (iVal != 0) {
1208 0 : uint16_t uiVal = *(reinterpret_cast<const uint16_t*>(&iVal));
1209 0 : auto sRet = static_cast<uint16_t>(uiVal >> static_cast<uint16_t>(BitShift::K_BIT_SHIFT15));
1210 0 : if (sRet != 0) {
1211 0 : int16_t iValM = -iVal;
1212 0 : uiVal = *(reinterpret_cast<uint16_t*>(&iValM));
1213 : }
1214 0 : SetValByUint16Val(uiVal, sRet, retVal);
1215 : }
1216 0 : return retVal;
1217 : }
1218 :
1219 40 : uint16_t half::UInt16ToFp16(const uint16_t& uiVal)
1220 : {
1221 40 : if (uiVal == 0) {
1222 4 : return 0;
1223 : } else {
1224 : uint16_t eRet;
1225 36 : uint16_t mRet = uiVal;
1226 36 : uint16_t mMin = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT);
1227 36 : uint16_t mMax = mMin << 1;
1228 36 : uint16_t len = static_cast<uint16_t>(GetManBitLength(mRet));
1229 36 : if (len > K_MAN_BIT_LENGTH) {
1230 22 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS) +
1231 : static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1232 : uint32_t mTrunc;
1233 22 : uint32_t truncMask = 1;
1234 22 : uint32_t eTmp = static_cast<uint32_t>(len - K_MAN_BIT_LENGTH);
1235 74 : for (uint32_t i = 1; i < eTmp; i++) {
1236 52 : truncMask = (truncMask << 1) + 1;
1237 : }
1238 22 : mTrunc = (mRet & truncMask) << (static_cast<uint32_t>(BitShift::K_BIT_SHIFT32) - eTmp);
1239 96 : for (uint32_t i = 0; i < eTmp; i++) {
1240 74 : mRet = (mRet >> 1);
1241 74 : eRet = eRet + 1;
1242 : }
1243 22 : bool bLastBit = ((mRet & 1) > 0);
1244 22 : bool bTruncHigh = static_cast<bool>(0);
1245 22 : bool bTruncLeft = static_cast<bool>(0);
1246 : if (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) { // trunc
1247 22 : bTruncHigh = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) > 0);
1248 22 : bTruncLeft = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX)) > 0);
1249 : }
1250 22 : mRet = ManRoundToNearest(bLastBit, bTruncHigh, bTruncLeft, mRet);
1251 28 : while (mRet >= mMax) {
1252 6 : mRet = mRet >> 1;
1253 6 : eRet = eRet + 1;
1254 : }
1255 22 : if (FP16_IS_INVALID(val)) {
1256 0 : val = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX);
1257 : }
1258 : } else {
1259 14 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS);
1260 14 : mRet = mRet << (static_cast<uint32_t>(DimIndex::K_DIM11) - static_cast<uint32_t>(len));
1261 14 : eRet = eRet + (len - static_cast<uint16_t>(1));
1262 : }
1263 36 : return FP16_CONSTRUCTOR(0u, eRet, mRet);
1264 : }
1265 : }
1266 :
1267 0 : static void SetValByUint32Val(const uint32_t& inputVal, const uint16_t& sign, uint16_t& retVal)
1268 : {
1269 : uint16_t eRet;
1270 0 : uint32_t mMin = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT);
1271 0 : uint32_t mMax = mMin << 1;
1272 0 : uint32_t mTmp = (inputVal & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX));
1273 0 : uint16_t len = static_cast<uint16_t>(GetManBitLength(mTmp));
1274 0 : if (len > static_cast<uint16_t>(DimIndex::K_DIM11)) {
1275 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS) +
1276 : static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1277 0 : uint32_t truncMask = 1;
1278 0 : uint32_t eTmp = len - static_cast<uint32_t>(DimIndex::K_DIM11);
1279 0 : for (uint32_t i = 1; i < eTmp; i++) {
1280 0 : truncMask = (truncMask << 1) + 1;
1281 : }
1282 0 : uint32_t mTrunc = (mTmp & truncMask) << (static_cast<uint32_t>(BitShift::K_BIT_SHIFT32) - eTmp);
1283 0 : for (uint32_t i = 0; i < eTmp; i++) {
1284 0 : mTmp = (mTmp >> 1);
1285 0 : eRet = eRet + 1;
1286 : }
1287 0 : bool bLastBit = ((mTmp & 1) > 0);
1288 0 : bool bTruncHigh = static_cast<bool>(0);
1289 0 : bool bTruncLeft = static_cast<bool>(0);
1290 : if (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) { // trunc
1291 0 : bTruncLeft = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX)) > 0);
1292 0 : bTruncHigh = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) > 0);
1293 : }
1294 0 : mTmp = ManRoundToNearest(bLastBit, bTruncHigh, bTruncLeft, mTmp);
1295 0 : while (mTmp >= mMax) {
1296 0 : eRet = eRet + 1;
1297 0 : mTmp = mTmp >> 1;
1298 : }
1299 0 : if (eRet >= static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP)) {
1300 0 : mTmp = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_MAN);
1301 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP) - 1;
1302 : }
1303 : } else {
1304 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS);
1305 0 : eRet = eRet + (len - 1);
1306 0 : mTmp = mTmp << (static_cast<uint32_t>(DimIndex::K_DIM11) - static_cast<uint32_t>(len));
1307 : }
1308 0 : auto mRet = static_cast<uint16_t>(mTmp);
1309 0 : retVal = FP16_CONSTRUCTOR(sign, eRet, mRet);
1310 0 : }
1311 :
1312 0 : uint16_t half::Int32ToFp16(const int32_t& iVal) const
1313 : {
1314 0 : uint16_t retVal = 0;
1315 0 : if (iVal != 0) {
1316 0 : uint32_t uiVal = *(reinterpret_cast<const uint32_t*>(&iVal));
1317 0 : auto sRet = static_cast<uint16_t>(uiVal >> static_cast<uint16_t>(BitShift::K_BIT_SHIFT31));
1318 0 : if (sRet != 0) {
1319 0 : int32_t iValM = -iVal;
1320 0 : uiVal = *(reinterpret_cast<uint32_t*>(&iValM));
1321 : }
1322 0 : SetValByUint32Val(uiVal, sRet, retVal);
1323 : }
1324 0 : return retVal;
1325 : }
1326 :
1327 0 : uint16_t half::UInt32ToFp16(const uint32_t& uiVal) const
1328 : {
1329 0 : if (uiVal == 0) {
1330 0 : return 0;
1331 : } else {
1332 : uint16_t eRet;
1333 0 : uint32_t mTmp = uiVal;
1334 0 : uint32_t mMin = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_HIDE_BIT);
1335 0 : uint32_t mMax = mMin << 1;
1336 0 : uint16_t len = static_cast<uint16_t>(GetManBitLength(mTmp));
1337 0 : if (len > static_cast<uint16_t>(DimIndex::K_DIM11)) {
1338 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS) +
1339 : static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAN_LEN);
1340 0 : uint32_t truncMask = 1;
1341 0 : uint16_t eTmp = len - static_cast<uint16_t>(DimIndex::K_DIM11);
1342 0 : for (uint16_t i = 1; i < eTmp; i++) {
1343 0 : truncMask = (truncMask << 1) + 1;
1344 : }
1345 0 : uint32_t mTrunc = (mTmp & truncMask)
1346 0 : << static_cast<uint32_t>(static_cast<uint16_t>(BitShift::K_BIT_SHIFT32) - eTmp);
1347 0 : for (uint16_t i = 0; i < eTmp; i++) {
1348 0 : mTmp = (mTmp >> 1);
1349 0 : eRet = eRet + 1;
1350 : }
1351 0 : bool bLastBit = ((mTmp & 1) > 0);
1352 0 : bool bTruncHigh = false;
1353 0 : bool bTruncLeft = false;
1354 : if (ROUND_MODE == TagFp16RoundMode::K_ROUND_TO_NEAREST) { // trunc
1355 0 : bTruncHigh = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_SIGN_MASK)) > 0);
1356 0 : bTruncLeft = ((mTrunc & static_cast<uint32_t>(Fp32BasicParam::K_FP32_ABS_MAX)) > 0);
1357 : }
1358 0 : mTmp = ManRoundToNearest(bLastBit, bTruncHigh, bTruncLeft, mTmp);
1359 0 : while (mTmp >= mMax) {
1360 0 : mTmp = mTmp >> 1;
1361 0 : eRet = eRet + 1;
1362 : }
1363 0 : if (eRet >= static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP)) {
1364 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_EXP) - 1;
1365 0 : mTmp = static_cast<uint16_t>(Fp16BasicParam::K_FP16_MAX_MAN);
1366 : }
1367 : } else {
1368 0 : eRet = static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_BIAS);
1369 0 : mTmp = mTmp << (static_cast<uint32_t>(DimIndex::K_DIM11) - static_cast<uint32_t>(len));
1370 0 : eRet = eRet + (len - static_cast<uint16_t>(1));
1371 : }
1372 0 : auto mRet = static_cast<uint16_t>(mTmp);
1373 0 : return FP16_CONSTRUCTOR(0u, eRet, mRet);
1374 : }
1375 : }
1376 :
1377 : // evaluation
1378 4 : half& half::operator=(const half& fp)
1379 : {
1380 4 : if (&fp == this) {
1381 0 : return *this;
1382 : }
1383 4 : val = fp.val;
1384 4 : return *this;
1385 : }
1386 0 : half& half::operator=(const float& fVal)
1387 : {
1388 0 : val = FloatToFp16(fVal);
1389 0 : return *this;
1390 : }
1391 2 : half& half::operator=(const double& dVal)
1392 : {
1393 2 : val = DoubleToFp16(dVal);
1394 2 : return *this;
1395 : }
1396 0 : half& half::operator=(const int8_t& iVal)
1397 : {
1398 0 : val = Int8ToFp16(iVal);
1399 0 : return *this;
1400 : }
1401 0 : half& half::operator=(const uint8_t& uiVal)
1402 : {
1403 0 : val = UInt8ToFp16(uiVal);
1404 0 : return *this;
1405 : }
1406 0 : half& half::operator=(const int16_t& iVal)
1407 : {
1408 0 : val = Int16ToFp16(iVal);
1409 0 : return *this;
1410 : }
1411 0 : half& half::operator=(const uint16_t& uiVal)
1412 : {
1413 0 : val = UInt16ToFp16(uiVal);
1414 0 : return *this;
1415 : }
1416 0 : half& half::operator=(const int32_t& iVal)
1417 : {
1418 0 : val = Int32ToFp16(iVal);
1419 0 : return *this;
1420 : }
1421 0 : half& half::operator=(const uint32_t& uiVal)
1422 : {
1423 0 : val = UInt32ToFp16(uiVal);
1424 0 : return *this;
1425 : }
1426 :
1427 : // convert
1428 12 : half::operator float() const { return Fp16ToFloat(val); }
1429 0 : half::operator double() const { return Fp16ToDouble(val); }
1430 0 : half::operator int8_t() const { return Fp16ToInt8(val); }
1431 0 : half::operator uint8_t() const { return Fp16ToUInt8(val); }
1432 0 : half::operator int16_t() const { return Fp16ToInt16(val); }
1433 12 : half::operator uint16_t() const { return Fp16ToUInt16(val); }
1434 0 : half::operator int32_t() const { return Fp16ToInt32(val); }
1435 0 : half::operator uint32_t() const { return Fp16ToUInt32(val); }
1436 :
1437 0 : int32_t half::IsInf() const
1438 : {
1439 0 : if (((val) & (static_cast<uint16_t>(Fp16BasicParam::K_FP16_ABS_MAX))) ==
1440 : static_cast<uint16_t>(Fp16BasicParam::K_FP16_EXP_MASK)) {
1441 0 : if (((static_cast<uint16_t>(Fp16BasicParam::K_FP16_SIGN_MASK)) & (val)) != 0) {
1442 0 : return -1;
1443 : } else {
1444 0 : return 1;
1445 : }
1446 : } else {
1447 0 : return 0;
1448 : }
1449 : }
1450 :
1451 6 : float half::ToFloat() const { return Fp16ToFloat(val); }
1452 2 : double half::ToDouble() const { return Fp16ToDouble(val); }
1453 2 : int8_t half::ToInt8() const { return Fp16ToInt8(val); }
1454 2 : uint8_t half::ToUInt8() const { return Fp16ToUInt8(val); }
1455 2 : int16_t half::ToInt16() const { return Fp16ToInt16(val); }
1456 2 : uint16_t half::ToUInt16() const { return Fp16ToUInt16(val); }
1457 12 : int32_t half::ToInt32() const { return Fp16ToInt32(val); }
1458 2 : uint32_t half::ToUInt32() const { return Fp16ToUInt32(val); }
1459 : // } // namespace float16
|