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