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 : #include "hifloat.h"
11 :
12 : #include <bitset>
13 : #include <limits>
14 : #include <unordered_map>
15 : #include "log/hdc_log.h"
16 :
17 : namespace Adx {
18 : constexpr int32_t FP8E8M0_EXPONENT_BIAS = 127U;
19 : constexpr size_t ONE_BYTE_BIT_NUM = 8U;
20 : constexpr uint32_t FP8E5M2_EXPONENT_BIT_NUM = 5U;
21 : constexpr uint32_t FP8E4M3_EXPONENT_BIT_NUM = 4U;
22 : constexpr int32_t HIFLOAT8_SUBNORMAL_NUM = 23;
23 :
24 : static std::unordered_map<std::string, float> g_adxMantissaMapB2f = {
25 : {"000", 0}, {"001", 0.125}, {"010", 0.25}, {"011", 0.375}, {"100", 0.5},
26 : {"101", 0.625}, {"110", 0.75}, {"111", 0.875}, {"00", 0}, {"01", 0.25},
27 : {"10", 0.5}, {"11", 0.75}, {"0", 0}, {"1", 0.5}
28 : };
29 :
30 : static std::unordered_map<std::string, float> g_adxPresetEncoedsMap = {
31 : {"00000000", 0}, {"10000000", std::numeric_limits<float>::quiet_NaN()},
32 : {"01101111", std::numeric_limits<float>::infinity()}, {"11101111", -std::numeric_limits<float>::infinity()}
33 : };
34 :
35 : static std::unordered_map<std::string, uint32_t> g_adxConventionalMap = {
36 : {"11", 4}, {"10", 3}, {"01", 2}, {"001", 1}, {"0001", 0}, {"0000", 0}
37 : };
38 :
39 45 : static inline std::string ByteToBinary(const uint8_t byte) {
40 45 : return std::bitset<ONE_BYTE_BIT_NUM>(byte).to_string();
41 : }
42 :
43 7 : int32_t HiFloat8::GetExponent(const std::string &binary) const
44 : {
45 7 : if (binary.length() == 0) {
46 1 : return 0;
47 : }
48 6 : int32_t symbol = binary.substr(0, 1) == "0" ? 1 : -1;
49 6 : std::string revisedBinary = "1" + binary.substr(1);
50 6 : return symbol * std::stoi(revisedBinary, nullptr, BASE_NUM);
51 6 : }
52 :
53 7 : float HiFloat8::GetMantissaField(const std::string &binary) const
54 : {
55 7 : return std::stoi(binary, nullptr, BASE_NUM) / static_cast<float>(pow(BASE_NUM, binary.length()));
56 : }
57 :
58 12 : float HiFloat8::GetValue() const
59 : {
60 12 : std::string bitString = ByteToBinary(val);
61 12 : float value = 0.0;
62 12 : if (g_adxPresetEncoedsMap.find(bitString) != g_adxPresetEncoedsMap.end()) {
63 4 : value = g_adxPresetEncoedsMap[bitString];
64 4 : return value;
65 : }
66 8 : if (bitString.length() == ONE_BYTE_BIT_NUM) {
67 8 : std::string symbolBit = bitString.substr(0, 1);
68 8 : int32_t signVal = symbolBit == "0" ? 1 : -1;
69 8 : std::string dotField;
70 8 : uint32_t dotVal = 0;
71 29 : for (const auto& pair : g_adxConventionalMap) {
72 29 : const std::string &dot = pair.first;
73 29 : if (bitString.substr(1).find(dot) == 0) {
74 8 : dotField = dot;
75 8 : dotVal = pair.second;
76 8 : break;
77 : }
78 : }
79 8 : if (dotField.empty()) {
80 0 : IDE_LOGE("No dot field was found.");
81 0 : return std::numeric_limits<float>::max();
82 : }
83 8 : if (dotField == "0000") {
84 1 : std::string mantissaBit = bitString.substr(1 + dotField.length());
85 1 : int32_t mantissaVal = std::stoi(mantissaBit, nullptr, BASE_NUM);
86 1 : value = signVal * static_cast<float>(pow(BASE_NUM, mantissaVal - HIFLOAT8_SUBNORMAL_NUM));
87 1 : return value;
88 1 : }
89 7 : int32_t exponentField = GetExponent(bitString.substr(1 + dotField.length(), dotVal));
90 7 : float mantissaField = GetMantissaField(bitString.substr(1 + dotField.length() + dotVal));
91 7 : value = signVal * static_cast<float>(pow(BASE_NUM, exponentField) * (1 + mantissaField));
92 9 : }
93 7 : return value;
94 12 : }
95 :
96 20 : float FpaEbMc::Decode(const std::string &bitString, const std::string &exponentBit, const std::string &mantissaBit,
97 : const uint32_t exponentBitNum) const
98 : {
99 20 : int32_t exponentBias = (1 << (exponentBitNum - 1)) - 1;
100 20 : int32_t signVal = std::stoi(bitString.substr(0, 1), nullptr, BASE_NUM);
101 20 : int32_t exponentVal = std::stoi(exponentBit, nullptr, BASE_NUM);
102 20 : bool isNormal = exponentVal == 0U ? false : true;
103 20 : float value = 0.0;
104 20 : if (isNormal) {
105 14 : value = static_cast<float>(
106 14 : pow(-1, signVal) * pow(BASE_NUM, exponentVal - exponentBias) * (1 + g_adxMantissaMapB2f[mantissaBit]));
107 : } else {
108 6 : value = static_cast<float>(
109 6 : pow(-1, signVal) * pow(BASE_NUM, exponentVal - exponentBias + 1) * g_adxMantissaMapB2f[mantissaBit]);
110 : }
111 20 : return value;
112 : }
113 :
114 12 : float Fp8E5M2::GetValue() const
115 : {
116 12 : std::string bitString = ByteToBinary(val);
117 12 : std::string exponentBit = bitString.substr(1, FP8E5M2_EXPONENT_BIT_NUM);
118 12 : std::string mantissaBit = bitString.substr(1 + FP8E5M2_EXPONENT_BIT_NUM);
119 12 : if (exponentBit == "11111" && mantissaBit == "00") {
120 2 : return static_cast<float>(pow(-1, std::stoi(bitString.substr(0, 1), nullptr, BASE_NUM))) *
121 1 : std::numeric_limits<float>::infinity();
122 11 : } else if (exponentBit == "11111") {
123 1 : return std::numeric_limits<float>::quiet_NaN();
124 : }
125 10 : return Decode(bitString, exponentBit, mantissaBit, FP8E5M2_EXPONENT_BIT_NUM);
126 12 : }
127 :
128 11 : float Fp8E4M3::GetValue() const
129 : {
130 11 : std::string bitString = ByteToBinary(val);
131 11 : std::string exponentBit = bitString.substr(1, FP8E4M3_EXPONENT_BIT_NUM);
132 11 : std::string mantissaBit = bitString.substr(1 + FP8E4M3_EXPONENT_BIT_NUM);
133 11 : if (exponentBit == "1111" && mantissaBit == "111") {
134 1 : return std::numeric_limits<float>::quiet_NaN();
135 : }
136 10 : return Decode(bitString, exponentBit, mantissaBit, FP8E4M3_EXPONENT_BIT_NUM);
137 11 : }
138 :
139 10 : float Fp8E8M0::GetValue() const
140 : {
141 10 : std::string bitString = ByteToBinary(val);
142 10 : float value = 0.0;
143 10 : std::string exponentBit = bitString.substr(0, ONE_BYTE_BIT_NUM);
144 10 : if (exponentBit == "11111111") {
145 1 : value = std::numeric_limits<float>::quiet_NaN();
146 1 : return value;
147 : }
148 : // exponentBit为空时stoi会抛异常,可以保证exponentBit不会为空
149 9 : int32_t exponentVal = std::stoi(exponentBit, nullptr, BASE_NUM);
150 9 : value = static_cast<float>(pow(BASE_NUM, exponentVal - FP8E8M0_EXPONENT_BIAS));
151 9 : return value;
152 10 : }
153 : }; // namespace
|