自编以e为底的指数函数exp,性能接近标准库函数

算法描述:
(1). 先做自变量x的范围检查,对于双精度浮点数,自变量不能超出(-1022ln2, 1024ln2)=(-708.39, 709.78),否则exp(x)会溢出。对于单精度浮点数,自变量不能超出(-126ln2, 128ln2)=(-87.33, 88.72). 自己使用此函数时,如果能通过其它途径保证自变量不会超出前述范围,那么可以省略这两个判断,提高速度。
(2). 令 x=k1·ln2+b1, 那么 e^x=2^{k_1}\cdot e^{b_1} ,其中k1为整数,可正可负,k_1=floor(\frac{x}{\ln 2}),\ b_1\in[0,\ln2) ,但是floor函数的调用代价极大(为什么floor()这么慢?-腾讯云 ,glibc/sysdeps/ieee754/dbl-64/s_floor.c GitHub),所以改用强制类型转换static_cast获得k1.
(3). b1的范围还是太大,如果直接对b1使用e^x在x=0处的泰勒级数,即使使用阶数很高的泰勒级数,精度也不够高,所以再做变换,令b_1=k_2 \cdot \frac{\ln2}{128} + b_2,\ \ k_2=0,1,2,\cdots,127,\ \ b_2\in [0,\frac{\ln2}{128} ) ,把 \exp(k_2 \cdot \frac{\ln2}{128}) 用数组存起来,然后对b2使用 e^x 在 x=0 处的泰勒级数:

e^{b_2}=1+b_2+\frac{b_2^2}{2!}+\frac{b_2^3}{3!}+\frac{b_2^4}{4!}+\frac{b_2^5}{5!}

多项式求值采用秦九韶算法,同时还使用fmadd指令加速运算(融合乘加,intel _mm_fmadd_sd )
(4). 不要用浮点乘法计算2^{k_1}\cdot e^{b_1},而是利用IEEE 754浮点数的格式,直接用位运算修改浮点数的阶码,不仅速度快,而且没有乘法的误差累积。

标准库的算法可参考:https://github.com/bminor/glibc/blob/master/sysdeps/ieee754/dbl-64/e_exp.c

最终的效果是,精度稍差于标准库,特别是自变量比较大时。速度十分接近标准库,当抛弃判断自变量是否在区间(-708.39, 709.78)内时,以及不对NAN情况进行处理,速度甚至稍快于标准库。

C++代码如下:

#include<stdio.h>
#include<math.h>
#include<time.h>
#include<immintrin.h>#define FMADDconstexpr double ln2 = 0.6931471805599453;
constexpr double ln2_128 = 0.0054152123481245727; // =(ln2)/128
constexpr double d1_ln2 = 1.4426950408889634;     // =1/ln2
constexpr double d128_ln2 = 184.6649652337873;    // =128/ln2// DBL_MIN = 2^(-1022)=2.2250738585072014e-308,  
// DBL_MAX = 2^1024   =1.7976931348623158e+308,两者均在float.h中定义
constexpr double ln_DBL_MIN = -708.39641853226411;  // =ln(DBL_MIN)= -1022*ln(2)
constexpr double ln_DBL_MAX = 709.78271289338400;   // =ln(DBL_MAX)=  1024*ln(2)__m128d c6 = _mm_set_sd(1.0 / 720.0);
__m128d c5 = _mm_set_sd(1.0 / 120.0);
__m128d c4 = _mm_set_sd(1.0 / 24.0);
__m128d c3 = _mm_set_sd(1.0 / 6.0);
__m128d c2 = _mm_set_sd(1.0 / 2.0);
__m128d c1 = _mm_set_sd(1.0);//exp(0),exp(ln2/128),exp(2*ln2/128),exp(3*ln2/128),...exp(127*ln2/128),
double expln2_128Array[128] = {
1.0,
1.0054299011128028, 1.0108892860517005, 1.0163783149109530,
1.0218971486541167, 1.0274459491187637, 1.0330248790212284,
1.0386341019613788, 1.0442737824274138, 1.0499440858006873,
1.0556451783605572, 1.0613772272892621, 1.0671404006768236,
1.0729348675259756, 1.0787607977571198, 1.0846183622133092,
1.0905077326652577, 1.0964290818163768, 1.1023825833078409,
1.1083684117236786, 1.1143867425958925, 1.1204377524096067,
1.1265216186082419, 1.1326385195987192, 1.1387886347566917,
1.1449721444318042, 1.1511892299529827, 1.1574400736337510,
1.1637248587775775, 1.1700437696832502, 1.1763969916502813,
1.1827847109843410, 1.1892071150027211, 1.1956643920398274,
1.2021567314527031, 1.2086843236265816, 1.2152473599804689,
1.2218460329727575, 1.2284805361068700, 1.2351510639369333,
1.2418578120734840, 1.2486009771892047, 1.2553807570246911,
1.2621973503942507, 1.2690509571917332, 1.2759417783963921,
1.2828700160787783, 1.2898358734066658, 1.2968395546510097,
1.3038812651919359, 1.3109612115247643, 1.3180796012660640,
1.3252366431597413, 1.3324325470831614, 1.3396675240533030,
1.3469417862329458, 1.3542555469368927, 1.3616090206382248,
1.3690024229745906, 1.3764359707545301, 1.3839098819638320,
1.3914243757719262, 1.3989796725383111, 1.4065759938190154,
1.4142135623730950, 1.4218926021691656, 1.4296133383919700,
1.4373759974489823, 1.4451808069770466, 1.4530279958490526,
1.4609177941806470, 1.4688504333369819, 1.4768261459394993,
1.4848451658727525, 1.4929077282912648, 1.5010140696264255,
1.5091644275934227, 1.5173590411982147, 1.5255981507445383,
1.5338819978409560, 1.5422108254079408, 1.5505848776850000,
1.5590044002378370, 1.5674696399655529, 1.5759808451078865,
1.5845382652524937, 1.5931421513422669, 1.6017927556826934,
1.6104903319492543, 1.6192351351948637, 1.6280274218573478,
1.6368674497669645, 1.6457554781539648, 1.6546917676561944,
1.6636765803267364, 1.6727101796415966, 1.6817928305074291,
1.6909247992693052, 1.7001063537185235, 1.7093377631004628,
1.7186192981224779, 1.7279512309618376, 1.7373338352737062,
1.7467673861991689, 1.7562521603732995, 1.7657884359332728,
1.7753764925265213, 1.7850166113189350, 1.7947090750031072,
1.8044541678066239, 1.8142521755003988, 1.8241033854070533,
1.8340080864093425, 1.8439665689586259, 1.8539791250833856,
1.8640460483977890, 1.8741676341102999, 1.8843441790323344,
1.8945759815869656, 1.9048633418176742, 1.9152065613971473,
1.9256059436361249, 1.9360617934922945, 1.9465744175792333,
1.9571441241754003, 1.9677712232331758, 1.9784560263879510,
1.9891988469672664 };double myexp(double x) {// 自己使用时如果确定x不会超出范围(-708.39, 709.78),// 可以去掉下面两个判断,提高速度//if (x < ln_DBL_MIN) {//	return 0;//}//if (x > ln_DBL_MAX) {//	return INFINITY;//}long long k1;if (x < 0){// k1 = floor(x * d1_ln2 - 1)// floor函数的耗时远远多于static_castk1 = static_cast<long long>(x * d1_ln2 - 1);}else {k1 = static_cast<long long>(x * d1_ln2);}x = x - k1 * ln2;//此时必有x>0//int k2 = floor(x * d128_ln2);int k2 = static_cast<int>(x * d128_ln2);x = x - k2 * ln2_128;double t;
#ifdef FMADD__m128d t128 = c5;__m128d x128 = _mm_set_sd(x);t128 = _mm_fmadd_sd(t128, x128, c4);t128 = _mm_fmadd_sd(t128, x128, c3);t128 = _mm_fmadd_sd(t128, x128, c2);t128 = _mm_fmadd_sd(t128, x128, c1);t128 = _mm_fmadd_sd(t128, x128, c1);t = _mm_cvtsd_f64(t128);
#elset = 1.0 / 24.0 + x * 1.0 / 120.0;t = 1.0 / 6.0 + x * t;t = 1.0 / 2.0 + x * t;t = 1.0  + x * t;t = 1.0  + x * t;
#endift *= expln2_128Array[k2];unsigned long long LLT = *reinterpret_cast<unsigned long long*>(&t);LLT += (k1 << 52);t = *reinterpret_cast<double*>(&LLT);return t;
}int main() {printf("double,精度测试\n");for (double x = -3.0; x < 2.0; x += 0.3) {printf("myexp(%2.1f)=%18.16lf\n  exp(%2.1f)=%18.16lf\n-------\n", x, myexp(x), x, exp(x));}for (double x = 3; x < 20; x += 1.0) {printf("myexp(%2.1f)=%18.16lf\n  exp(%2.1f)=%18.16lf\n-------\n", x, myexp(x), x, exp(x));}//----------------------double x1 = -70.0, x2 = 70.0, dx = 1e-7;printf("速度测试,x1 = %4.2f, x2 = %4.2f, 编译器优化设为/O2, Core i7-11800H \n",x1,x2);clock_t start = clock();double sum = 0.0;for (double x = x1; x < x2; x += dx) {sum += myexp(x);}printf("sum=%lf,  myexp_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);start = clock();sum = 0.0;for (double x = x1; x < x2; x += dx) {sum += exp(x);}printf("sum=%lf,    exp_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);
}

结果如下:

double型,精度测试
myexp(-3.0)=0.0497870683678639exp(-3.0)=0.0497870683678639
-------
myexp(-2.7)=0.0672055127397497exp(-2.7)=0.0672055127397498
-------
myexp(-2.4)=0.0907179532894125exp(-2.4)=0.0907179532894125
-------
myexp(-2.1)=0.1224564282529818exp(-2.1)=0.1224564282529818
-------
myexp(-1.8)=0.1652988882215864exp(-1.8)=0.1652988882215864
-------
myexp(-1.5)=0.2231301601484297exp(-1.5)=0.2231301601484297
-------
myexp(-1.2)=0.3011942119122020exp(-1.2)=0.3011942119122020
-------
myexp(-0.9)=0.4065696597405990exp(-0.9)=0.4065696597405989
-------
myexp(-0.6)=0.5488116360940263exp(-0.6)=0.5488116360940263
-------
myexp(-0.3)=0.7408182206817177exp(-0.3)=0.7408182206817177
-------
myexp(-0.0)=0.9999999999999997exp(-0.0)=0.9999999999999997
-------
myexp(0.3)=1.3498588075760027exp(0.3)=1.3498588075760027
-------
myexp(0.6)=1.8221188003905087exp(0.6)=1.8221188003905082
-------
myexp(0.9)=2.4596031111569490exp(0.9)=2.4596031111569490
-------
myexp(1.2)=3.3201169227365468exp(1.2)=3.3201169227365468
-------
myexp(1.5)=4.4816890703380636exp(1.5)=4.4816890703380636
-------
myexp(1.8)=6.0496474644129448exp(1.8)=6.0496474644129448
-------
myexp(3.0)=20.0855369231876679exp(3.0)=20.0855369231876679
-------
myexp(4.0)=54.5981500331442362exp(4.0)=54.5981500331442362
-------
myexp(5.0)=148.4131591025766284exp(5.0)=148.4131591025765999
-------
myexp(6.0)=403.4287934927352239exp(6.0)=403.4287934927351102
-------
myexp(7.0)=1096.6331584284587279exp(7.0)=1096.6331584284585006
-------
myexp(8.0)=2980.9579870417278471exp(8.0)=2980.9579870417283018
-------
myexp(9.0)=8103.0839275753914990exp(9.0)=8103.0839275753842230
-------
myexp(10.0)=22026.4657948067251709exp(10.0)=22026.4657948067178950
-------
myexp(11.0)=59874.1417151978530455exp(11.0)=59874.1417151978166657
-------
myexp(12.0)=162754.7914190039737150exp(12.0)=162754.7914190039155073
-------
myexp(13.0)=442413.3920089205494151exp(13.0)=442413.3920089204912074
-------
myexp(14.0)=1202604.2841647767927498exp(14.0)=1202604.2841647767927498
-------
myexp(15.0)=3269017.3724721106700599exp(15.0)=3269017.3724721106700599
-------
myexp(16.0)=8886110.5205078702419996exp(16.0)=8886110.5205078721046448
-------
myexp(17.0)=24154952.7535753361880779exp(17.0)=24154952.7535752989351749
-------
myexp(18.0)=65659969.1373304873704910exp(18.0)=65659969.1373305097222328
-------
myexp(19.0)=178482300.9631871581077576exp(19.0)=178482300.9631872475147247
-------
速度测试,x1 = -70.00, x2 = 70.00, 编译器优化设为/O2, Core i7-11800H
sum=25154387663949415049142870006785114112.000000,  myexp_Time: 5.674000s
sum=25154387663949410326776387137139900416.000000,    exp_Time: 5.728000s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/59215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

es安装拼音分词后Kibana出现内存错误

出现错误 今天在安装es的拼音分词器&#xff0c;并重启es容器后&#xff0c;登录Kibana无法使用&#xff0c;查询日志发现如下报错 Waiting until all Elasticsearch nodes are compatible with Kibana before starting saved objects migrations... | typelog timestamp2024…

前端react面试基础知识(II)

这些问题涵盖了 React 的很多核心概念和实际应用场景。下面是针对每个问题的详细回答&#xff1a; 1. **React 项目中&#xff0c;如何动态改变组件的 class 来切换样式?** 可以通过条件判断或者状态&#xff08;state&#xff09;来动态改变组件的 class。例如&#xff0c;使…

Day 42 || 完全背包、518. 零钱兑换 II 、 377. 组合总和 Ⅳ、70. 爬楼梯 (进阶)

完全背包 题目链接&#xff1a;卡码网第52题 思路&#xff1a;和之前01背包一样&#xff0c;但是物品可以无限放置&#xff0c;所以之前二维数组中的背包容量是倒序遍历的&#xff0c;现在可以正序遍历即可重复放入。 import java.util.Scanner; public class Main {public …

数据结构-二叉树中的递归

目录 前言 简单手撕二叉树 二叉树节点的求解 二叉树叶子节点的求解 二叉树高度 二叉树第K层节点的个数 二叉树查找值为X的节点 结束语 前言 在这里说声抱歉&#xff0c;好久没更新数据结构了&#xff0c;二叉树的相关内容还没有更新完&#xff0c;是小编的失职&#xff…

在基于AWS EC2的云端k8s环境中 搭建开发基础设施

中间件下载使用helm,这里部署的都是单机版的 aws-ebs-storageclass.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata:name: aws-ebs-storageclass provisioner: kubernetes.io/aws-ebs parameters:type: gp2 # 选择合适的 EBS 类型&#xff0c;如 gp2、io1…

Apache Calcite - 查询优化之自定义优化规则

RelOptRule简介 为了自定义优化规则&#xff0c;我们需要继承RelOptRule类。org.apache.calcite.plan.RelOptRule 是 Apache Calcite 中的一个抽象类&#xff0c;用于定义优化规则。优化规则是用于匹配查询计划中的特定模式&#xff0c;并将其转换为更优化的形式的逻辑。通过继…

2024网鼎杯青龙组wp:Crypto1

题目 附件内容如下 from Crypto.Util.number import * from secret import flag from Cryptodome.PublicKey import RSAp getPrime(512) q getPrime(512) n p * q d getPrime(299) e inverse(d,(p-1)*(q-1)) m bytes_to_long(flag) c pow(m,e,n) hint1 p >> (51…

Python 单元测试中的 Mocking 与 Stubbing:提高测试效率的关键技术

在软件开发过程中&#xff0c;单元测试是确保代码质量的重要环节。为了实现高效的单元测试&#xff0c;我们常常需要隔离待测试的代码与其外部依赖。这时候&#xff0c;Mocking&#xff08;模拟&#xff09;和 Stubbing&#xff08;桩&#xff09;技术就显得尤为重要。这两种技…

Golang | Leetcode Golang题解之第528题按权重随机选择

题目&#xff1a; 题解&#xff1a; type Solution struct {pre []int }func Constructor(w []int) Solution {for i : 1; i < len(w); i {w[i] w[i-1]}return Solution{w} }func (s *Solution) PickIndex() int {x : rand.Intn(s.pre[len(s.pre)-1]) 1return sort.Searc…

3D打印机 屏幕的固定挂钩断后的一次自己修复经历

引子 3D打印机的屏幕固定挂钩断了 这次确实不知道咋断的&#xff0c;这可咋办呢&#xff0c;到网上看了一下&#xff0c;一个屏幕要2佰多&#xff0c;有些小贵&#xff0c;要不就自己修修吧&#xff0c;打个挂钩按上&#xff0c;说干就干。 正文 freecad的设计图如下【其中各…

PHP合成图片,生成海报图,poster-editor使用说明

之前写过一篇使用Grafika插件生成海报图的文章&#xff0c;但是当我再次使用时&#xff0c;却发生了错误&#xff0c;回看Grafika文档&#xff0c;发现很久没更新了&#xff0c;不兼容新版的GD&#xff0c;所以改用了intervention/image插件来生成海报图。 但是后来需要对海报…

Java基于微信小程序的美食推荐系统(附源码,文档)

博主介绍&#xff1a;✌程序猿徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Linux的IP网路命令: 用于显示和操作网络接口(网络设备)的命令ip link详解

目录 一、概述 二、用法 1、基本语法 2、常用选项 3、常用参数 4、获取帮助 三、示例 1. 显示所有网络接口的信息 &#xff08;1&#xff09;命令 &#xff08;2&#xff09;输出示例 &#xff08;3&#xff09;实际操作 2. 启动网络接口 3. 停止网络接口 4. 更改…

【驱动】地平线X3交叉编译工具搭建、源码下载

1、交叉编译工具搭建 1)安装依赖包 sudo apt-get install -y build-essential make cmake libpcre3 libpcre3-dev bc bison \ flex python3-numpy mtd-utils zlib1g-dev debootstrap \ libdata-hexdumper-perl libncurses5-dev zip qemu-user-static \ curl repo git liblz4…

服务器上清理Docker容器运行日志的正确方法

为啥要清理服务器上docker容器的日志 因为是服务器的磁盘空间资源有限&#xff0c;由于docker容器在启动的时候没有限制&#xff0c;导致运行的docker容器随着时间的推移产生的日志越来越多&#xff0c;最后把服务磁盘资源耗尽&#xff0c;服务器的磁盘满了会导致服务器的应用无…

C语言 | Leetcode C语言题解之第526题优美的排列

题目&#xff1a; 题解&#xff1a; int countArrangement(int n) {int f[1 << n];memset(f, 0, sizeof(f));f[0] 1;for (int mask 1; mask < (1 << n); mask) {int num __builtin_popcount(mask);for (int i 0; i < n; i) {if (mask & (1 <<…

SpringBoot篇(自动装配原理)

目录 一、自动装配机制 1. 简介 2. 自动装配主要依靠三个核心的关键技术 3. run()方法加载启动类 4. 注解SpringBootApplication包含了多个注解 4.1 SpringBootConfiguration 4.2 ComponentScan 4.3 EnableAutoConfiguration 5. SpringBootApplication一共做了三件事 …

3D Gaussian Splatting代码详解(二):模型构建

3 模型构建 gaussians GaussianModel(dataset.sh_degree) 3.1 初始化函数 __init__ 构造函数 构造函数 __init__ 的主要作用是初始化 3D 高斯模型的各项参数和激活函数&#xff0c;用于生成 3D 空间中的高斯表示。 初始化球谐函数的参数&#xff1a; self.active_sh_degre…

HarmonyOS-权限管理

一. 权限分类 1. system_grant system_grant 为系统授权&#xff0c;无需询问用户&#xff0c;常用的权限包括网络请求、获取网络信息、获取wifi信息、获取传感器数据等。 /* system_grant&#xff08;系统授权&#xff09;*/static readonly INTERNET ohos.permission.INTE…

如何在 linux 中使用 /etc/fstab 挂载远程共享 ?

在 Linux 领域&#xff0c;高效的管理文件系统和数据存储对于用户和管理员来说&#xff0c;是一项基本技能。 有一种特别有用的技术涉及自动建立远程共享&#xff0c;允许无缝访问网络存储&#xff0c;就好像是本地的一样。 本指南将引导您完成使用 /etc/fstab 文件以自动远程…