当前位置: 首页 > news >正文

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

算法描述:
(1). 先做自变量x的范围检查,不能出现负数和0. 自己使用时,如果能通过其它途径保证自变量为正,那么可以省略这两个判断,提高速度。
(2). 根据IEEE 754浮点数的格式,x=2^k \cdot m,\ m\in(1,2),则 ln(x)=kln(2)+ln(m),可以通过位运算方便快速地获取k和m .
(3). 把 ln(1+x) 和 ln(1-x) 在 x=0 处的泰勒级数相减,

\ln(1+x) =x-\frac{x^2}{2}+\frac{x^3}{3}-\frac{x^4}{4}+\cdots

\ln(1-x) =-x-\frac{x^2}{2}-\frac{x^3}{3}-\frac{x^4}{4}-\cdots

\ln\frac{1+x}{1-x}=2x+\frac{2x^3}{3}+\frac{2x^5}{5}+\cdots

因为m的范围是(1, 2),不够接近1,如果直接令m=(1+x)/(1-x),那么x不够接近0,代入上面的泰勒级数,则精度不够高,所以要对m进行变换,常见的做法是乘上sqrt(2)/2,即

\ln(x)=k\ln(2)+\ln(m) \\ =k\ln(2)+\ln(\sqrt{2})+\ln(\frac{\sqrt{2}}{2}m) \\ =(k+\frac{1}{2})\ln(2)+\ln(\frac{\sqrt{2}}{2}m)

\frac{\sqrt{2}}{2}m\in(\frac{\sqrt{2}}{2}, \sqrt{2}),\quad x=\frac{\frac{\sqrt{2}}{2}m-1}{\frac{\sqrt{2}}{2}m+1} \in(-(3-2\sqrt{2}),3-2\sqrt{2}) 

如果改为乘以 2/3,则

\frac{2}{3}m\in(\frac{2}{3}, \frac{4}{3}),\quad x=\frac{\frac{2}{3}m-1}{\frac{2}{3}m+1} \in(-\frac{1}{5},\frac{1}{7})

这个区间长度为12/35=0.34285714,比区间(-(3-2\sqrt{2}),3-2\sqrt{2})的长度6-4\sqrt{2}=0.34314575更短,代入泰勒级数后的精度更高一些。

\ln(x)=k\ln(2)+\ln(m) \\ =k\ln(2)+\ln(\frac{3}{2})+\ln(\frac{2}{3}m)
多项式求值采用秦九韶算法,同时还使用fmadd指令加速运算(融合乘加,intel _mm_fmadd_sd)

计算机如何计算对数函数_数值计算】求对数函数值,输入实数x>0 ,输出x对应的对数函数值ln(x)(使用双精度dou-CSDN博客更详细地解释了如何利用IEEE 754浮点数的格式获取k和m.

标准库的算法可参考:glibc/sysdeps/ieee754/dbl-64/s_log1p.c at master · bminor/glibc · GitHub

最终的效果是,精度与标准库互有胜负(以windows的计算器以及Wolfram|Alpha: Computational Intelligence作为参考值),如果不对自变量为NAN的情况进行处理,速度稍快于标准库。

 C++代码如下:

#include<stdio.h>
#include<math.h>
#include<time.h>
#include<immintrin.h>#define FMADD
constexpr double ln2 = 0.6931471805599453;
constexpr double ln3_2 = 0.40546510810816438;   // ln(3/2)
constexpr double sqrt2_2 = 0.7071067811865475;  // sqrt(2)/2
constexpr unsigned long long x000F = 0x000FFFFFFFFFFFFF;
constexpr unsigned long long x3FF0 = 0x3FF0000000000000;__m128d c17 = _mm_set_sd(2.0 / 17.0);
__m128d c15 = _mm_set_sd(2.0 / 15.0);
__m128d c13 = _mm_set_sd(2.0 / 13.0);
__m128d c11 = _mm_set_sd(2.0 / 11.0);
__m128d c9 = _mm_set_sd(2.0 / 9.0);
__m128d c7 = _mm_set_sd(2.0 / 7.0);
__m128d c5 = _mm_set_sd(2.0 / 5.0);
__m128d c3 = _mm_set_sd(2.0 / 3.0);
__m128d c1 = _mm_set_sd(2.0);inline double myln(double x) {if (x < 0) {return NAN;}if (x == 0) {return -INFINITY;}unsigned long long llx = *reinterpret_cast<unsigned long long*>(&x);short k = (llx >> 52) - 1023;        //  x = 2^k * munsigned long long llm = (llx & x000F) | x3FF0;double m = *reinterpret_cast<double*>(&llm);m *= 0.66666666666666666;    //m *= sqrt2_2;x = (m - 1.0) / (m + 1.0);double x2 = x * x;
#ifdef FMADD__m128d x128 = _mm_set_sd(x);__m128d x2_128 = _mm_set_sd(x2);__m128d t128 = c17;t128 = _mm_fmadd_sd(t128, x2_128, c15);t128 = _mm_fmadd_sd(t128, x2_128, c13);t128 = _mm_fmadd_sd(t128, x2_128, c11);t128 = _mm_fmadd_sd(t128, x2_128, c9);t128 = _mm_fmadd_sd(t128, x2_128, c7);t128 = _mm_fmadd_sd(t128, x2_128, c5);t128 = _mm_fmadd_sd(t128, x2_128, c3);t128 = _mm_fmadd_sd(t128, x2_128, c1);t128 = _mm_mul_sd(t128, x128);m = _mm_cvtsd_f64(t128);
#elsem = 2.0 / 17.0;m = m * x2 + 2.0 / 15.0;m = m * x2 + 2.0 / 13.0;m = m * x2 + 2.0 / 11.0;m = m * x2 + 2.0 / 9.0;m = m * x2 + 2.0 / 7.0;m = m * x2 + 2.0 / 5.0;m = m * x2 + 2.0 / 3.0;m = m * x2 + 2.0;m *= x;
#endifreturn k * ln2 + ln3_2 + m;  // return (k + 0.5) * ln2 + m; //如果前面 m *= sqrt2_2,那就需要用这一行return
}int main() {printf("double, 精度测试\n");for (double x = 0.1; x < 3; x += 0.1) {printf("myln(%2.1f)=%18.16lf\n  ln(%2.1f)=%18.16lf\n-------\n", x, myln(x), x, log(x));}printf("速度测试,编译器优化设为/O2,CPU:Core i7-11800H \n");clock_t start = clock();double sum = 0;double x1 = 0.01, x2 =1000, dx = 1e-6;for (double x = x1; x < x2; x += dx) {sum += myln(x) / x;}printf("sum=%lf, myln_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);start = clock();sum = 0;for (double x = x1; x < x2; x += dx) {sum += log(x) / x;}printf("sum=%lf,   ln_Time: %fs\n", sum, (double)(clock() - start) / CLOCKS_PER_SEC);
}

 运行结果如下:

double, 精度测试
myln(0.1)=-2.3025850929940459ln(0.1)=-2.3025850929940455
-------
myln(0.2)=-1.6094379124341003ln(0.2)=-1.6094379124341003
-------
myln(0.3)=-1.2039728043259359ln(0.3)=-1.2039728043259359
-------
myln(0.4)=-0.9162907318741550ln(0.4)=-0.9162907318741550
-------
myln(0.5)=-0.6931471805599396ln(0.5)=-0.6931471805599453
-------
myln(0.6)=-0.5108256237659907ln(0.6)=-0.5108256237659907
-------
myln(0.7)=-0.3566749439387324ln(0.7)=-0.3566749439387324
-------
myln(0.8)=-0.2231435513142100ln(0.8)=-0.2231435513142098
-------
myln(0.9)=-0.1053605156578265ln(0.9)=-0.1053605156578264
-------
myln(1.0)=-0.0000000000000002ln(1.0)=-0.0000000000000001
-------
myln(1.1)=0.0953101798043247ln(1.1)=0.0953101798043247
-------
myln(1.2)=0.1823215567939545ln(1.2)=0.1823215567939546
-------
myln(1.3)=0.2623642644674911ln(1.3)=0.2623642644674911
-------
myln(1.4)=0.3364722366212130ln(1.4)=0.3364722366212130
-------
myln(1.5)=0.4054651081081644ln(1.5)=0.4054651081081646
-------
myln(1.6)=0.4700036292457357ln(1.6)=0.4700036292457357
-------
myln(1.7)=0.5306282510621706ln(1.7)=0.5306282510621706
-------
myln(1.8)=0.5877866649021192ln(1.8)=0.5877866649021193
-------
myln(1.9)=0.6418538861723950ln(1.9)=0.6418538861723950
-------
myln(2.0)=0.6931471805599509ln(2.0)=0.6931471805599455
-------
myln(2.1)=0.7419373447293780ln(2.1)=0.7419373447293776
-------
myln(2.2)=0.7884573603642703ln(2.2)=0.7884573603642705
-------
myln(2.3)=0.8329091229351041ln(2.3)=0.8329091229351043
-------
myln(2.4)=0.8754687373539001ln(2.4)=0.8754687373539003
-------
myln(2.5)=0.9162907318741552ln(2.5)=0.9162907318741554
-------
myln(2.6)=0.9555114450274365ln(2.6)=0.9555114450274368
-------
myln(2.7)=0.9932517730102837ln(2.7)=0.9932517730102838
-------
myln(2.8)=1.0296194171811583ln(2.8)=1.0296194171811586
-------
myln(2.9)=1.0647107369924285ln(2.9)=1.0647107369924287
-------
速度测试,编译器优化设为/O2,CPU:Core i7-11800H
sum=13254515.057331, myln_Time: 3.817000s
sum=13254515.057331,   ln_Time: 3.838000s

相关文章:

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

算法描述&#xff1a; (1). 先做自变量x的范围检查&#xff0c;不能出现负数和0. 自己使用时&#xff0c;如果能通过其它途径保证自变量为正&#xff0c;那么可以省略这两个判断&#xff0c;提高速度。 (2). 根据IEEE 754浮点数的格式&#xff0c;&#xff0c;则 ln(x)kln(2)ln…...

Java中的日期时间

JDK8之前常用的日期时间类 System.currentTimeMillis()&#xff1a;获取当前毫秒数&#xff08;long类型&#xff09; java.util.Date&#xff1a;通用Date类 import java.util.Date;Date date new Date(); // 空参构造器 System.out.println(date.getTime()); // 获取当前时…...

位置编码的表示

位置编码的表示位置编码的表示位置编码的表示位置编码的表示位置编码的表示...

0,国产FPGA(紫光同创)-新建PDS工程

国产FPGA正在蓬勃发展&#xff0c;紫光同创FPGA是大家竞赛时经常遇到的一款国产FPGA&#xff0c;本专栏从IP核开始一直到后续图像处理等。 开发板&#xff1a;盘古50K标准板 1&#xff0c;新建PDS工程 点击File&#xff08;1&#xff09;&#xff0c;然后是New Projects&#…...

c++联合

结构体与联合体的区别 结构体(struct)中所有变量是“共存”的——优点是“有容乃大”&#xff0c;全面&#xff1b;缺点是struct内存空间的分配是粗放的&#xff0c;不管用不用&#xff0c;全分配。 而联合体(union)中是各变量是“互斥”的——缺点就是不够“包容”&#xff…...

Edit Data. Create Cell Editors. Validate User Input 编辑数据。创建 Cell Editors。验证用户输入

Goto Data Grid 数据网格 Edit Data. Create Cell Editors. Validate User Input 编辑数据。创建 Cell Editors。验证用户输入 Get and Modify Cell Values in Code 在代码中获取和修改单元格值 仅当 Grid 及其列已完全初始化时&#xff0c;才使用以下方法。如果需要在表单仍…...

Java 文件操作与IO流

文件 文件有两个概念&#xff0c;在广义来看就是操作系统上对硬件和软件资源抽象为文件。 在侠义上来看&#xff0c;就是我们保存在硬盘上的文件 在这里我们讨论的是狭义的文件&#xff0c;在外面的硬盘上的文件细分又可以分为二进制文件和文本文件&#xff0c;文本文件可以通…...

探索开源MiniMind项目:让大语言模型不再神秘(1)

简介&#xff1a; 声明&#xff1a;本人非此项目作者&#xff0c;仅仅是探索项目&#xff0c;分享项目。如有不妥&#xff0c;请联系我删除&#xff01; 原项目地址&#xff1a;GitHub - jingyaogong/minimind: 「大模型」3小时完全从0训练26M的小参数GPT&#xff0c;个人显卡即…...

Android 大疆面经

Android 大疆面经 文章目录 Android 大疆面经一面 一面 自我介绍问项目聊了10分钟View的绘制流程MVC&#xff0c;MVP&#xff0c;MVVM的区别view和viewmodel的通信&#xff0c;除了databing还有其他的方式面向对象和面向过程的区别工厂模式和策略模式&#xff0c;哪些框架使用…...

【2024-10-31-2024-11-03】LeetCode刷题——python语法基础题

&#x1f4dd;前言说明&#xff1a; ●本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;主要跟随B站作者灵茶山的视频进行学习&#xff0c;专栏中一篇文章为B站对应的一个视频 题目主要为B站视频内涉及的题目以及B站视频中提到的“课后作业”。 ●文章中的理…...

【算法】二分查找

目录 一、概念 二、思路 三、边界问题 一、概念 在一本书中查找某一页&#xff0c;我们总是倾向于先翻到整本书的中间&#xff0c;然后根据当前页数判断我们想要找的页在当前页的左半本中还是右半本中&#xff0c;接着继续翻到剩下半本书的中间...... 这就是二分查找思想在…...

第十五章 Vue工程化开发及Vue CLI脚手架

目录 一、引言 二、Vue CLI 基本介绍 三、安装Vue CLI 3.1. 安装npm和yarn 3.2. 安装Vue CLI 3.3. 查看 Vue 版本 四、创建启动工程 4.1. 创建项目架子 4.2. 启动工程 五、脚手架目录文件介绍 六、核心文件讲解 6.1. index.html 6.2. main.js 6.3. App.vue 一、…...

【Grafana】Grafana 基础入门

Grafana 简介 什么是Grafana Grafana 是一跨平台的开源的可视化分析工具&#xff0c;是目前网络架构和应用分析中最流行的时序数据展示工具&#xff0c;主要用于大规模指标数据的可视化展示。 它是用Go语言开发&#xff0c;可以做数据监控和数据统计&#xff0c;带有告警功能…...

如何获取页面上所有input框

要获取页面上所有的<input>框&#xff0c;你可以使用JavaScript。这通常可以通过查询DOM&#xff08;文档对象模型&#xff09;来实现&#xff0c;有几种方法可以做到这一点&#xff0c;包括使用document.querySelectorAll、document.getElementsByTagName或document.get…...

0-ARM Linux驱动开发-字符设备

一、字符设备概述 Linux 系统中&#xff0c;设备被分为字符设备、块设备和网络设备等。字符设备以字节流的方式进行数据传输&#xff0c;数据的访问是按顺序的&#xff0c;一个字节一个字节地进行读取和写入操作&#xff0c;没有缓冲区。例如&#xff0c;终端&#xff08;/dev…...

使用 Faster Whisper 和 Gradio 实现实时语音转文字

随着人工智能技术的进步&#xff0c;语音识别已经成为最热门的研究领域之一。如何实现高效、准确的实时语音转文字功能&#xff0c;是许多开发者关注的重点。本文将介绍如何使用 Faster Whisper 和 Gradio 这两个强大工具&#xff0c;快速构建一个实时语音转文字应用。 Faster…...

redis v6.0.16 安装 基于Ubuntu 22.04

redis安装 基于Ubuntu 22.04 本文演示如何在ubuntu22.04下&#xff0c;安装redis v6.0.16&#xff0c;并配置测试远程访问。 Step1 更新环境 sudo apt updateStep2 安装redis sudo apt install redis-server -yStep3 启动 sudo systemctl restart redissudo systemctl sta…...

Milvus - 内存索引类型详解

1. 背景概述 在大规模数据处理和向量相似性搜索场景中&#xff0c;内存索引的使用显著提升了查询速度和效率。Milvus 提供了多种内存索引类型&#xff0c;以满足不同场景下的性能需求。本文将介绍 Milvus 支持的各种内存索引类型及其适用场景、配置参数和使用方法。 2. 为什么…...

【STM32】按键控制LED 光敏传感器控制蜂鸣器

文章目录 前置知识按键介绍传感器模块硬件电路按键硬件电路传感器模块硬件电路 C语言数据类型在Keil中的对应写法C语言枚举 按键控制LED接线图Hardware文件夹&#xff08;模块化编程&#xff09;LED驱动程序封装Key(按键)驱动程序封装 main.c源文件 光敏传感器控制蜂鸣器接线图…...

flutter-防抖

在Flutter中实现输入框的防抖功能&#xff0c;通常是为了减少用户输入时触发的事件数量&#xff0c;特别是在进行网络请求时。防抖&#xff08;Debounce&#xff09;意味着在用户停止输入一段时间后才触发事件。以下是实现输入框防抖的一种方法&#xff1a; 1、使用Debounce类…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...