- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我已经使用查找表和低阶多项式近似实现了定点 log2 函数,但对整个 32 位定点范围 [-1,+1) 的准确度不太满意。输入格式为 s0.31,输出格式为 s15.16。
我在这里发布这个问题,以便其他用户可以发布他的答案(一些评论在另一个线程中交换,但他们更喜欢在单独的线程中提供全面的答案)。欢迎任何其他答案,如果您能提供一些算法及其实现的速度与准确度的详细信息,我将不胜感激。
谢谢。
最佳答案
通过简单地计算定点数中的前导零位 x
,可以确定log2(x)
到最接近的严格较小的整数。在许多处理器体系结构上,存在“计数前导零”机器指令或内在指令。如果这不可用,则相当有效地实现 clz()
可以通过多种方式构建,其中一种包含在下面的代码中。
为了计算对数的小数部分,两个主要的明显竞争者是表格中的插值和极小极大多项式近似。在这种特定情况下,在相当小的表中进行二次插值似乎是更有吸引力的选择。 x = 2i * (1+f),其中 0 ≤ f < 1。我们确定 i
如上所述并使用 f
的前导位索引到表中。抛物线通过这个和下面的两个表格条目拟合,即时计算抛物线的参数。结果被四舍五入,并应用启发式调整以部分补偿定点算术的截断性质。最后,将整数部分相加,产生最终结果。
应该注意,计算涉及可能为负的有符号整数的右移。我们需要将这些右移映射到机器代码级别的算术右移,即 不是 由 ISO-C 标准保证。然而,在实践中,大多数编译器会做我们想要的。在本例中,我在运行 Windows 的 x64 平台上使用了英特尔编译器。
用32位字的66项表,最大绝对误差可以降低到8.18251e-6,所以满s15.16
精度达到。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#define FRAC_BITS_OUT (16)
#define INT_BITS_OUT (15)
#define FRAC_BITS_IN (31)
#define INT_BITS_IN ( 0)
/* count leading zeros: intrinsic or machine instruction on many architectures */
int32_t clz (uint32_t x)
{
uint32_t n, y;
n = 31 + (!x);
if ((y = (x & 0xffff0000U))) { n -= 16; x = y; }
if ((y = (x & 0xff00ff00U))) { n -= 8; x = y; }
if ((y = (x & 0xf0f0f0f0U))) { n -= 4; x = y; }
if ((y = (x & 0xccccccccU))) { n -= 2; x = y; }
if (( (x & 0xaaaaaaaaU))) { n -= 1; }
return n;
}
#define LOG2_TBL_SIZE (6)
#define TBL_SIZE ((1 << LOG2_TBL_SIZE) + 2)
/* for i = [0,65]: log2(1 + i/64) * (1 << 31) */
const uint32_t log2Tab [TBL_SIZE] =
{
0x00000000, 0x02dcf2d1, 0x05aeb4dd, 0x08759c50,
0x0b31fb7d, 0x0de42120, 0x108c588d, 0x132ae9e2,
0x15c01a3a, 0x184c2bd0, 0x1acf5e2e, 0x1d49ee4c,
0x1fbc16b9, 0x22260fb6, 0x24880f56, 0x26e2499d,
0x2934f098, 0x2b803474, 0x2dc4439b, 0x30014ac6,
0x32377512, 0x3466ec15, 0x368fd7ee, 0x38b25f5a,
0x3acea7c0, 0x3ce4d544, 0x3ef50ad2, 0x40ff6a2e,
0x43041403, 0x450327eb, 0x46fcc47a, 0x48f10751,
0x4ae00d1d, 0x4cc9f1ab, 0x4eaecfeb, 0x508ec1fa,
0x5269e12f, 0x5440461c, 0x5612089a, 0x57df3fd0,
0x59a80239, 0x5b6c65aa, 0x5d2c7f59, 0x5ee863e5,
0x60a02757, 0x6253dd2c, 0x64039858, 0x65af6b4b,
0x675767f5, 0x68fb9fce, 0x6a9c23d6, 0x6c39049b,
0x6dd2523d, 0x6f681c73, 0x70fa728c, 0x72896373,
0x7414fdb5, 0x759d4f81, 0x772266ad, 0x78a450b8,
0x7a231ace, 0x7b9ed1c7, 0x7d17822f, 0x7e8d3846,
0x80000000, 0x816fe50b
};
#define RND_SHIFT (31 - FRAC_BITS_OUT)
#define RND_CONST ((1 << RND_SHIFT) / 2)
#define RND_ADJUST (0x10d) /* established heuristically */
/*
compute log2(x) in s15.16 format, where x is in s0.31 format
maximum absolute error 8.18251e-6 @ 0x20352845 (0.251622232)
*/
int32_t fixed_log2 (int32_t x)
{
int32_t f1, f2, dx, a, b, approx, lz, i, idx;
uint32_t t;
/* x = 2**i * (1 + f), 0 <= f < 1. Find i */
lz = clz (x);
i = INT_BITS_IN - lz;
/* normalize f */
t = (uint32_t)x << (lz + 1);
/* index table of log2 values using LOG2_TBL_SIZE msbs of fraction */
idx = t >> (32 - LOG2_TBL_SIZE);
/* difference between argument and smallest sampling point */
dx = t - (idx << (32 - LOG2_TBL_SIZE));
/* fit parabola through closest three sampling points; find coeffs a, b */
f1 = (log2Tab[idx+1] - log2Tab[idx]);
f2 = (log2Tab[idx+2] - log2Tab[idx]);
a = f2 - (f1 << 1);
b = (f1 << 1) - a;
/* find function value for argument by computing ((a*dx+b)*dx) */
approx = (int32_t)((((int64_t)a)*dx) >> (32 - LOG2_TBL_SIZE)) + b;
approx = (int32_t)((((int64_t)approx)*dx) >> (32 - LOG2_TBL_SIZE + 1));
approx = log2Tab[idx] + approx;
/* round fractional part of result */
approx = (((uint32_t)approx) + RND_CONST + RND_ADJUST) >> RND_SHIFT;
/* combine integer and fractional parts of result */
return (i << FRAC_BITS_OUT) + approx;
}
/* convert from s15.16 fixed point to double-precision floating point */
double fixed_to_float_s15_16 (int32_t a)
{
return a / 65536.0;
}
/* convert from s0.31 fixed point to double-precision floating point */
double fixed_to_float_s0_31 (int32_t a)
{
return a / (65536.0 * 32768.0);
}
int main (void)
{
double a, res, ref, err, maxerr = 0.0;
int32_t x, start, end;
start = 0x00000001;
end = 0x7fffffff;
printf ("testing fixed_log2 with inputs in [%17.10e, %17.10e)\n",
fixed_to_float_s0_31 (start), fixed_to_float_s0_31 (end));
for (x = start; x < end; x++) {
a = fixed_to_float_s0_31 (x);
ref = log2 (a);
res = fixed_to_float_s15_16 (fixed_log2 (x));
err = fabs (res - ref);
if (err > maxerr) {
maxerr = err;
}
}
printf ("max. err = %g\n", maxerr);
return EXIT_SUCCESS;
}
log2(x)
的典型计算方法是使用 x = 2i * (1+f) 并对 [√½, √2] 中的 (1+f) 使用 log2(1+f) 的近似值,这意味着我们使用多项式
p(f)
在初级近似区间 [√½-1, √2-1] 上。
mulhi
的限制下,中间计算尽可能地扩大操作数以提高准确性。操作作为其基本构建块,因为这是许多 32 位体系结构上的 native 指令,可通过内联机器代码或作为内在指令访问。与基于表的代码一样,有符号数据的右移可能为负,并且这种右移必须映射到算术右移,这是 ISO-C 不保证但大多数 C 编译器可以保证的。
s15.16
准确性,但比基于表格的变体略差。我怀疑我应该在多项式中添加一个额外的项。
/* on 32-bit architectures, there is often an instruction/intrinsic for this */
int32_t mulhi (int32_t a, int32_t b)
{
return (int32_t)(((int64_t)a * (int64_t)b) >> 32);
}
#define RND_SHIFT (25 - FRAC_BITS_OUT)
#define RND_CONST ((1 << RND_SHIFT) / 2)
#define RND_ADJUST (-2) /* established heuristically */
/*
compute log2(x) in s15.16 format, where x is in s0.31 format
maximum absolute error 1.11288e-5 @ 0x5a82689f (0.707104757)
*/
int32_t fixed_log2 (int32_t x)
{
int32_t lz, i, f, p, approx;
uint32_t t;
/* x = 2**i * (1 + f), 0 <= f < 1. Find i */
lz = clz (x);
i = INT_BITS_IN - lz;
/* force (1+f) into range [sqrt(0.5), sqrt(2)] */
t = (uint32_t)x << lz;
if (t > (uint32_t)(1.414213562 * (1U << 31))) {
i++;
t = t >> 1;
}
/* compute log2(1+f) for f in [-0.2929, 0.4142] */
f = t - (1U << 31);
p = + (int32_t)(-0.206191055 * (1U << 31) - 1);
p = mulhi (p, f) + (int32_t)( 0.318199910 * (1U << 30) - 18);
p = mulhi (p, f) + (int32_t)(-0.366491705 * (1U << 29) + 22);
p = mulhi (p, f) + (int32_t)( 0.479811855 * (1U << 28) - 2);
p = mulhi (p, f) + (int32_t)(-0.721206390 * (1U << 27) + 37);
p = mulhi (p, f) + (int32_t)( 0.442701618 * (1U << 26) + 35);
p = mulhi (p, f) + (f >> (31 - 25));
/* round fractional part of the result */
approx = (p + RND_CONST + RND_ADJUST) >> RND_SHIFT;
/* combine integer and fractional parts of result */
return (i << FRAC_BITS_OUT) + approx;
}
关于logarithm - 定点中的 Log2 近似,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54661131/
我有两个分数列表; 说 A = [ 1/212, 5/212, 3/212, ... ] 和 B = [ 4/143, 7/143, 2/143, ... ] . 如果我们定义 A' = a[0] *
我有两个分数列表; 说 A = [ 1/212, 5/212, 3/212, ... ] 和 B = [ 4/143, 7/143, 2/143, ... ] . 如果我们定义 A' = a[0] *
我已经使用查找表和低阶多项式近似实现了定点 log2 函数,但对整个 32 位定点范围 [-1,+1) 的准确度不太满意。输入格式为 s0.31,输出格式为 s15.16。 我在这里发布这个问题,以便
以下示例来自 here ,和here我试过这个: log2(x) := log(x) / log(2); log2(8), float; 但这并没有给出 3,而是得到 log(8)/log(2)。 最
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve th
请原谅,我的数学一直很差,现在正尝试通过编码来学习一些 Python(以及一些数学)。 我有这个: import numpy as np import matplotlib.pyplot as plt
我有一个二维数组,其中每个元素都是一个傅立叶变换。我想“对数地”分割变换。例如,让我们将这些数组中的一个命名为 a : a = np.arange(0, 512) # I want to split
这是我在某个网站上看到的面试问题。 有人提到,答案涉及形成 log2() 的递归,如下所示: double log2(double x ) { if ( x1e-7) { do
我有一个数据文件,我正在从中创建直方图。 数据文件是: -0.1 0 0 JANE 1 1 1 BILL 2 2 1 BILL 1 3 1 BILL 6 4 0 JANE
我正在尝试优化一个音频算法,它必须在每个步骤中计算如下两种算法。现在我已经读到,没有在多项式时间内运行的对数算法。我的问题是,通过查找表计算所有对数是否有意义,因为它们总是相同的,尽管存在大量内存访问
math.exp() 不适用于复数: >>> math.exp (math.pi*1j) Traceback (most recent call last): File "", line 1, i
随着时间的推移,我有一堆测量值,我想在 R 中绘制它们。这是我的数据示例。对于 4 个时间点,我有 6 个测量值: values <- c (1012.0, 1644.9, 837.0, 1200.9
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 8 年前。 Improve t
我有一些数据绘制在半对数图上(log-lin 样式,在 y 轴上具有对数刻度)。有没有办法将 y 轴刻度标签从实际值更改为对数值? 例如,考虑以下代码: import matplotlib.pyplo
我找不到这个问题的确切答案,所以我把它贴在这里:如果我有一个整数范围,我想以相等的对数距离计算该范围内的“N”个数字。 这是一个示例代码,用于查找相等的“非对数”距离(或多或少)的数字: const
我一直在学习 Python 2.5.4,我有以下问题需要解决: "编写一个程序,计算从 2 到某个数 n 的所有素数的对数和,并打印出素数的对数和、数 n 以及这两个量的比值。测试这适用于不同的 n
是否可以像下图那样使用对数刻度的颜色条级别? 这是一些可以实现的示例代码: import matplotlib.pyplot as plt import numpy as np from matplo
从这篇非常好的帖子开始 Logarithmic scale in Java FX 2 我已经更改了这个类以获得 Y 轴上的对数刻度,并且它工作正常。我唯一的问题是水平网格线很少,比例总是从 0 或接近
我正在尝试找到用 C 语言计算以下内容的最快方法: p = 2^(ceil(log2(x))); 到目前为止,通过查看 Stack overflow(和其他地方)中的答案,我已经做到了这一点: #de
我试图在 sympy 中求解一个简单的对数方程,但是当我尝试执行代码时,我得到了一个RuntimeError: maximum recursion depth exceeded。这是我正在做的: im
我是一名优秀的程序员,十分优秀!