关于float /double、string类型的hash函数/hash表实现

本文详细介绍了在C++中实现高效数值比较、浮点数与双精度数的精确比较方法,并通过哈希映射技术进行优化。重点讨论了数值比较的误差容忍、哈希函数的设计与应用,旨在提升复杂数据结构处理的性能。
部署运行你感兴趣的模型镜像

#include <ext/hash_map>
#include <math.h>
using namespace std;
using namespace __gnu_cxx;

#define FLT_EPSILON 1.192093e-007
#define DBL_EPSILON 2.2204460492503131e-016
#define FLOAT_EPSILON(a,b) ( a > b ? fabs(a) * FLT_EPSILON : fabs(b) * FLT_EPSILON)
#define DOUBLE_EPSILON(a,b) ( a > b ? fabs(a) * FLT_EPSILON : fabs(b) * DBL_EPSILON)
#define float_equal(a, b) (fabs((a)-(b)) <= FLOAT_EPSILON(a,b))
#define double_equal(a, b) (fabs((a)-(b)) <= DOUBLE_EPSILON(a,b))
#define INT64_MAX 0x7fffffffffffffffLL

typedef struct
{
 size_t operator()(const double & dValue) const
  {   
    int e = 0 ;
    double tmp = dValue;
    if (dValue<0)
    {
     tmp = -dValue;
    }
    e = ceil (log (dValue));
    return size_t(( INT64_MAX+ 1.0) * tmp * exp (-e));
  }
} hash_double;

typedef struct
{
  bool operator()(const double &value1,const double &value2) const
   {
     return double_equal(value1,value2);
   }
} hash_double_cmp;

typedef struct
{
   size_t operator()(const string & str) const
   {
     size_t h=0;for(size_t i=0;i<str.length();++i)
     {
      h = ( h<<5 ) - h + str[i];
     }
     return h;
     //return __stl_hash_string(str.c_str());
   }
} hash_string;


typedef struct
{
   bool operator()(const string &str1,const string &str2) const
   {
     return str1.compare(str2) == 0;
    }
} hash_str_cmp;

hash_map<double, vector,hash_double,hash_double_cmp> m_doubleMap;
hash_map<string, vector,hash_string,hash_str_cmp> m_strMap;

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

#include "pch.h" #include "TCalcFuncSets.h" #include <windows.h> #include <string> #include <vector> #include <fstream> #include <sstream> #include <map> #include <algorithm> #include <iostream> #include <cmath> #include <cctype> #include <unordered_map> #include <mutex> #include <memory> // 用于std::make_shared #include <chrono> // 用于std::chrono时间功能 // 缓存项结构体 struct CacheEntry { std::map<std::string, float> data; std::chrono::steady_clock::time_point lastAccessed; CacheEntry() : lastAccessed(std::chrono::steady_clock::now()) {} }; // 统一的缓存管理类 class QuantileCache { private: std::unordered_map<std::string, CacheEntry> cache_; std::mutex mutex_; const size_t maxCacheSize_ = 100; // 最大缓存项数量 public: // 尝试从缓存获取数据 bool tryGet(const std::string& key, std::map<std::string, float>& result) { std::lock_guard<std::mutex> lock(mutex_); auto it = cache_.find(key); if (it != cache_.end()) { // 更新访问时间 it->second.lastAccessed = std::chrono::steady_clock::now(); result = it->second.data; return true; } return false; } // 存储数据到缓存 void put(const std::string& key, const std::map<std::string, float>& data) { std::lock_guard<std::mutex> lock(mutex_); // 清理过期缓存项 if (cache_.size() >= maxCacheSize_) { evictOldEntries(); } cache_[key].data = data; cache_[key].lastAccessed = std::chrono::steady_clock::now(); } private: // 移除最旧的缓存项 void evictOldEntries() { // 找到最旧的缓存项 auto oldestIt = cache_.begin(); for (auto it = cache_.begin(); it != cache_.end(); ++it) { if (it->second.lastAccessed < oldestIt->second.lastAccessed) { oldestIt = it; } } // 移除最旧的缓存项 cache_.erase(oldestIt); } }; // 全局缓存实例 static QuantileCache g_quantileCache; // 清理字符串中的空白字符 std::string CleanString(const std::string& str) { std::string result; result.reserve(str.size()); for (unsigned int i = 0; i < str.size(); i++) { char c = str[i]; if (!std::isspace((unsigned char)c)) { result.push_back(c); } } return result; } // 清理路径中的无效字符 std::string CleanPath(const std::string& path) { std::string result; result.reserve(path.size()); for (unsigned int i = 0; i < path.size(); i++) { char c = path[i]; if (c == ' ' || !std::isspace((unsigned char)c)) { result.push_back(c); } } return result; } // 将通达信日期格式转换为标准日期格式(yyyymmdd) std::string ConvertTDXDateToYYYYMMDD(float tdxDate) { int dateInt = (int)tdxDate + 19000000; if (dateInt <= 19000000 || dateInt > 21000000) { return ""; } char buffer[16]; sprintf_s(buffer, sizeof(buffer), "%d", dateInt); return std::string(buffer); } // 快速解析日期字符串 std::string ParseDateString(const std::string& dateStr) { // 移除引号 std::string cleaned = dateStr; if (!cleaned.empty() && cleaned[0] == '"') { cleaned = cleaned.substr(1); } if (!cleaned.empty() && cleaned[cleaned.length() - 1] == '"') { cleaned = cleaned.substr(0, cleaned.length() - 1); } // 如果已经是yyyymmdd格式 if (cleaned.length() == 8 && cleaned.find_first_not_of("0123456789") == std::string::npos) { return cleaned; } // 处理分隔符格式 int year = 0, month = 0, day = 0; size_t firstDelim = cleaned.find_first_of("-/\/"); if (firstDelim != std::string::npos) { size_t secondDelim = cleaned.find_first_of("-/\/", firstDelim + 1); if (secondDelim != std::string::npos) { year = atoi(cleaned.substr(0, firstDelim).c_str()); month = atoi(cleaned.substr(firstDelim + 1, secondDelim - firstDelim - 1).c_str()); day = atoi(cleaned.substr(secondDelim + 1).c_str()); } } else if (cleaned.length() == 8) { year = atoi(cleaned.substr(0, 4).c_str()); month = atoi(cleaned.substr(4, 2).c_str()); day = atoi(cleaned.substr(6, 2).c_str()); } if (year > 1900 && year < 2100 && month >= 1 && month <= 12 && day >= 1 && day <= 31) { char buffer[16]; sprintf_s(buffer, sizeof(buffer), "%04d%02d%02d", year, month, day); return std::string(buffer); } return ""; } // 处理单个CSV文件并提取指定列的数据 bool ProcessSingleCSVFileForColumn(const std::string& filePath, std::map<std::string, std::vector<double> >& dateColumnMap, int columnIdx) { std::ifstream inFile(filePath.c_str()); if (!inFile.is_open()) { return false; } // 跳过头 std::string headerLine; if (!std::getline(inFile, headerLine)) { inFile.close(); return false; } std::string line; while (std::getline(inFile, line)) { std::istringstream lineIss(line); std::string token; int columnIndex = 0; std::string dateStr; double columnValue = 0.0; bool hasValue = false; while (std::getline(lineIss, token, ',')) { std::string cleanedToken = CleanString(token); if (columnIndex == 0) { // date列 dateStr = ParseDateString(cleanedToken); } else if (columnIndex == columnIdx) { // 指定列 if (!cleanedToken.empty()) { columnValue = atof(cleanedToken.c_str()); hasValue = true; } } columnIndex++; } // 只有当日期有效且指定列有值时才添加 if (!dateStr.empty() && hasValue) { dateColumnMap[dateStr].push_back(columnValue); } } inFile.close(); return true; } // 处理单个CSV文件并计算N日涨跌幅 bool ProcessSingleCSVFileForReturns(const std::string& filePath, std::map<std::string, std::vector<double> >& dateReturnsMap, int N) { std::ifstream inFile(filePath.c_str()); if (!inFile.is_open()) { return false; } // 跳过头 std::string headerLine; if (!std::getline(inFile, headerLine)) { inFile.close(); return false; } // 预分配向量空间以提高性能 std::vector<std::string> dates; std::vector<double> closePrices; dates.reserve(1000); // 预估每只股票约1000个交易日 closePrices.reserve(1000); std::string line; while (std::getline(inFile, line)) { std::istringstream lineIss(line); std::string token; int columnIndex = 0; std::string dateStr; double closePrice = 0.0; while (std::getline(lineIss, token, ',')) { std::string cleanedToken = CleanString(token); if (columnIndex == 0) { // date列 dateStr = ParseDateString(cleanedToken); } else if (columnIndex == 5) { // close列 if (!cleanedToken.empty()) { closePrice = atof(cleanedToken.c_str()); } } columnIndex++; } dates.push_back(dateStr); closePrices.push_back(closePrice); } inFile.close(); // 计算N日涨跌幅 for (unsigned int i = N; i < closePrices.size(); i++) { if (!dates[i].empty() && closePrices[i] > 0 && closePrices[i - N] > 0) { double returnRate = (closePrices[i] - closePrices[i - N]) / closePrices[i - N] * 100.0; dateReturnsMap[dates[i]].push_back(returnRate); } } return true; } // 优化的文件处理函数 - 用于计算指定列的分位数 void ReadCSVAndCalculateColumnData(const std::string& directory, std::map<std::string, std::vector<double> >& dateColumnMap, int columnIdx) { WIN32_FIND_DATAA findData; std::string cleanedDirectory = CleanPath(directory); std::string searchPath = cleanedDirectory + "\\*.csv"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return; } do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { std::string fileName(findData.cFileName); std::string filePath = cleanedDirectory + "\\" + fileName; filePath = CleanPath(filePath); ProcessSingleCSVFileForColumn(filePath, dateColumnMap, columnIdx); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); } // 优化的文件处理函数 - 用于计算N日涨跌幅 void ReadCSVAndCalculateReturns(const std::string& directory, std::map<std::string, std::vector<double> >& dateReturnsMap, int N) { WIN32_FIND_DATAA findData; std::string cleanedDirectory = CleanPath(directory); std::string searchPath = cleanedDirectory + "\\*.csv"; HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) { return; } do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { std::string fileName(findData.cFileName); std::string filePath = cleanedDirectory + "\\" + fileName; filePath = CleanPath(filePath); ProcessSingleCSVFileForReturns(filePath, dateReturnsMap, N); } } while (FindNextFileA(hFind, &findData) != 0); FindClose(hFind); } // 函数前向声明 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile ); template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile, std::map<std::string, std::vector<double>>& dateDataMap ); float CalculateQuantile(const std::vector<double>& data, float quantile); // 通用分位数数据处理函数 // 提取两个主要函数的公共数据处理逻辑 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile ) { // 存储日期对应的数据 std::map<std::string, std::vector<double>> dateDataMap; // 调用传入的函数读取数据 readDataFunc(csvDirectory, dateDataMap); // 计算每个日期的分位数 for (const auto& entry : dateDataMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } // 清理数据以释放内存 dateDataMap.clear(); } // 兼容不同参数类型的重载版本 template <typename DataReaderFunc> void ProcessQuantileData( const std::string& csvDirectory, std::map<std::string, float>& dateQuantileMap, DataReaderFunc readDataFunc, float quantile, std::map<std::string, std::vector<double>>& dateDataMap ) { // 调用传入的函数读取数据 readDataFunc(csvDirectory, dateDataMap); // 计算每个日期的分位数 for (const auto& entry : dateDataMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } } // 计算分位数 - 使用O(n)时间复杂度的优化算法 float CalculateQuantile(const std::vector<double>& data, float quantile) { if (data.empty()) { return 0.0f; } if (quantile < 0.0f) quantile = 0.0f; if (quantile > 1.0f) quantile = 1.0f; std::vector<double> sortedData = data; size_t n = sortedData.size(); double pos = quantile * (n - 1); int lowerIndex = static_cast<int>(pos); int upperIndex = lowerIndex + 1; // 对于精确索引的情况,直接使用nth_element if (lowerIndex == upperIndex || upperIndex >= static_cast<int>(n)) { std::nth_element(sortedData.begin(), sortedData.begin() + lowerIndex, sortedData.end()); return static_cast<float>(sortedData[lowerIndex]); } // 对于需要插值的情况,找到两个位置的元素 // 先找lowerIndex位置的元素 std::nth_element(sortedData.begin(), sortedData.begin() + lowerIndex, sortedData.end()); double lowerValue = sortedData[lowerIndex]; // 再在lowerIndex之后的范围内找upperIndex位置的元素 std::nth_element(sortedData.begin() + lowerIndex + 1, sortedData.begin() + upperIndex, sortedData.end()); double upperValue = sortedData[upperIndex]; // 线性插值计算最终分位数值 double fractionalPart = pos - lowerIndex; double quantileValue = lowerValue + fractionalPart * (upperValue - lowerValue); return static_cast<float>(quantileValue); } // 生成缓存键值 std::string GenerateColumnCacheKey(int columnIdx, float quantile) { char buffer[64]; sprintf_s(buffer, "column_%d_%.2f", columnIdx, quantile); return std::string(buffer); } std::string GenerateReturnsCacheKey(int N, float quantile) { char buffer[64]; sprintf_s(buffer, "returns_%d_%.2f", N, quantile); return std::string(buffer); } // 函数2 - 计算指定列的分位数 void CalculateColumnQuantileReturns(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc) { // 初始化输出数组为0 for (int i = 0; i < DataLen; i++) { pfOUT[i] = 0.0f; } // 获取列索引和分位数参数 int columnIdx = (int)(pfINb[0] + 0.5f); // M参数示列号 float quantile = pfINc[0]; // N参数示分位数 // 生成缓存键值,添加前缀以区分不同类型的缓存 std::string cacheKey = "column:" + GenerateColumnCacheKey(columnIdx, quantile); // 检查缓存中是否已有计算结果 std::map<std::string, float> dateQuantileMap; bool hasCache = g_quantileCache.tryGet(cacheKey, dateQuantileMap); // 如果缓存中没有,则进行计算 if (!hasCache) { // 设置CSV文件的目录 const std::string csvDirectory = "F:\\His_STOCKDATA"; // 使用堆分配存储日期对应的指定列数据,避免栈溢出 auto dateColumnMap = std::make_shared<std::map<std::string, std::vector<double>>>(); // 读取CSV文件并提取指定列的数据 ReadCSVAndCalculateColumnData(csvDirectory, *dateColumnMap, columnIdx); // 计算每个日期的分位数 for (const auto& entry : *dateColumnMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, quantile); } // 自动释放内存(通过shared_ptr的作用域) // 将结果存入缓存 g_quantileCache.put(cacheKey, dateQuantileMap); } // 将结果匹配到输出数组 for (int i = 0; i < DataLen; i++) { std::string dateStr = ConvertTDXDateToYYYYMMDD(pfINa[i]); if (dateStr.empty() || dateStr.length() != 8) { pfOUT[i] = 0.0f; continue; } std::map<std::string, float>::const_iterator iter = dateQuantileMap.find(dateStr); if (iter != dateQuantileMap.end()) { pfOUT[i] = iter->second; } else { pfOUT[i] = 0.0f; } } } // 函数3 - 快速计算分位数收益 void CalculateQuantileReturns(int DataLen, float* pfOUT, float* pfINa, float* pfINb, float* pfINc) { // 初始化输出数组为0 for (int i = 0; i < DataLen; i++) { pfOUT[i] = 0.0f; } // 获取N和M的值 int N = (int)(pfINb[0] + 0.5f); float M = pfINc[0]; // 生成缓存键值,添加前缀以区分不同类型的缓存 std::string cacheKey = "returns:" + GenerateReturnsCacheKey(N, M); // 检查缓存中是否已有计算结果 std::map<std::string, float> dateQuantileMap; bool hasCache = g_quantileCache.tryGet(cacheKey, dateQuantileMap); // 如果缓存中没有,则进行计算 if (!hasCache) { // 设置CSV文件的目录 const std::string csvDirectory = "F:\\His_STOCKDATA"; // 使用堆分配存储日期对应的涨跌幅数据,避免栈溢出 auto dateReturnsMap = std::make_shared<std::map<std::string, std::vector<double>>>(); // 读取CSV文件并计算N日涨跌幅 ReadCSVAndCalculateReturns(csvDirectory, *dateReturnsMap, N); // 计算每个日期的分位数 for (const auto& entry : *dateReturnsMap) { dateQuantileMap[entry.first] = CalculateQuantile(entry.second, M); } // 自动释放内存(通过shared_ptr的作用域) // 将结果存入缓存 g_quantileCache.put(cacheKey, dateQuantileMap); } // 将结果匹配到输出数组 for (int i = 0; i < DataLen; i++) { std::string dateStr = ConvertTDXDateToYYYYMMDD(pfINa[i]); if (dateStr.empty() || dateStr.length() != 8) { pfOUT[i] = 0.0f; continue; } std::map<std::string, float>::const_iterator iter = dateQuantileMap.find(dateStr); if (iter != dateQuantileMap.end()) { pfOUT[i] = iter->second; } else { pfOUT[i] = 0.0f; } } } // 函数注册 PluginTCalcFuncInfo g_CalcFuncSets[] = { {2, (pPluginFUNC)CalculateColumnQuantileReturns}, {3, (pPluginFUNC)CalculateQuantileReturns}, {0, NULL}, }; BOOL RegisterTdxFunc(PluginTCalcFuncInfo** pFun) { if (*pFun == NULL) { (*pFun) = g_CalcFuncSets; return TRUE; } return FALSE; }有哪些值得优化的地方
最新发布
09-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值