- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
基本上,我一直在尝试制作两个近似函数。在这两种情况下,我都输入了“x”和“y”组件(以处理那些讨厌的 n/0 和 0/0 条件),并且需要获得 Signed Char 输出。在 ATAN2 的情况下,它应该提供 +/-PI 的范围,而在 ATAN 的情况下,范围应该是 +/- PI/2。
我整个昨天都在努力思考它。在 excel 中玩弄之后找到一个基于近似的整体好的算法:
X * (PI/4 + 0.273 * (1 - |X|)) * 128/PI // Scale factor at end to switch to char format
我想出了以下代码:
signed char nabsSC(signed char x)
{
if(x > 0)
return -x;
return x;
}
signed char signSC(signed char input, signed char ifZero = 0, signed char scaleFactor = 1)
{
if(input > 0)
{return scaleFactor;}
else if(input < 0)
{return -scaleFactor;}
else
{return ifZero;}
}
signed char divisionSC(signed char numerator, signed char denominator)
{
if(denominator == 0) // Error Condition
{return 0;}
else
{return numerator/denominator;}
}
//#######################################################################################
signed char atan2SC(signed char y, signed char x)
{
// @todo make clearer : the code was deduced through trial and error in excel with brute force... not the best reasoning in the world but hey ho
if((x == y) && (x == 0)) // Error Condition
{return 0;}
// Prepare for algorithm Choice
const signed char X = abs(x);
signed char Y = abs(y);
if(Y > 2)
{Y = (Y << 1) + 4;}
const signed char alpha1 = 43;
const signed char alpha2 = 11;
// Make Choice
if(X <= Y) // x/y Path
{
const signed char beta = 64;
const signed char a = divisionSC(x,y); // x/y
const signed char A = nabsSC(a); // -|x/y|
const signed char temp = a * (alpha1 + alpha2 * A); // (x/y) * (32 + ((0.273 * 128) / PI) * (1 - |x/y|)))
// Small angle approximation of ARCTAN(X)
if(y < 0) // Determine Quadrant
{return -(temp + beta);}
else
{return -(temp - beta);}
}
else // y/x Path
{
const signed char a = divisionSC(y,x); // y/x
const signed char A = nabsSC(a); // -|y/x|
const signed char temp = a * (alpha1 + alpha2 * A); // (y/x) * (32 + ((0.273 * 128) / PI) * (1 - |y/x|)))
// Small angle approximation of ARCTAN(X)
if(x < 0) // Determine Quadrant
{
Y = signSC(y, -127, 127); // Sign(y)*127, if undefined: use -127
return temp + Y;
}
else
{return temp;}
}
}
令我绝望的是,实现中的误差大到 180 度,而且几乎到处都是。 (我将其与转换为 signed char 格式后的库中的 ATAN2F 进行了比较。)
我从这个网站得到了一般要点:http://geekshavefeelings.com/posts/fixed-point-atan2
谁能告诉我哪里出错了?以及我应该如何处理 ATAN 变体(它应该更精确,因为它看起来超过了范围的一半)而没有所有这些疯狂。
我目前在 Windows 上使用 QT Creator 4.8.1。这个特定代码位的终端平台最终将是一个没有 FPU 的微 Controller ,而 ATAN 功能将是使用的主要功能之一。因此,具有合理误差的效率(ATAN2 为 +/-2 度,ATAN 为 +/-1 度。这些是目前的估计,所以我可能会增加范围,但是,90 度绝对不能接受!)游戏的。
在此先感谢您提供的所有帮助!
编辑:澄清一下,ATAN2 和 ATAN 的输出都是一个 signed char 值,但是这两种类型的范围是不同的范围。
ATAN2 的范围从 -128 (-PI) 到 127 (+PI - PI/128)。
ATAN 的范围从 -128 (-PI/2) 到 127 (+PI/2 - PI/256)。
因此两者的输出值可以认为是两种不同的数据类型。
抱歉造成任何混淆。
EDIT2:将隐式 int 数字显式转换为带符号的 char 常量。
最佳答案
大纲如下。以下是附加信息。
结果角度(二进制角度测量)精确在数学上将单位圆分成 8 个楔形。假设 -128 到 127 char
,对于 atan2SC()
,每个八分圆的结果是 33 个整数:0 到 32 + 一个偏移量。 (0 到 32,而不是 0 到 31,因为四舍五入。)对于 atan2SC()
,结果是 0 到 64。所以只关注用 x 计算 1 主八分圆的结果,y
输入和 0 到 64 的结果。 atan2SC()
和 atan2SC()
都可以使用这个辅助函数 at2()
。对于 atan2SC()
,要找到中间角 a
,请使用 a = at2(x,y)/2
。对于 atanSC()
,使用 a = at2(-128, y)
。
用 a = divisionSC(x,y)
求整数商,然后用 a * (43 + 11 * A)
会丢失太多信息分配。需要使用使用 x,y
的方程找到 atan2 近似值,格式可能为 at2 = (a*y*y + b*y)/(c*x*x + d *x)
.
与 nabsSC()
一样,最好使用负绝对值。整数的负范围达到或超过正范围。例如-128 到 -1 与 1 到 127。调用 at2()
时使用负数和 0。
[编辑]
下面是带有简化的八分圆选择算法的代码。它经过精心构造,以确保 x,y
的任何否定都将导致 SCHAR_MIN,SCHAR_MAX
范围 - 假设 2 的补码。所有八分圆都调用 iat2()
并且可以在此处进行改进以提高精度。注意:iat2()
除以 x==0
被阻止,因为此时 x
不为 0。根据舍入模式以及此辅助函数是否与 atanSC()
共享,将决定其详细信息。建议 2 段线性表是宽整数数学不可用,否则线性 (ay+b)/(cx+d)
。我可能会更多地玩这个。
精度与性能的权衡对于 OP 的代码来说是至关重要的,但传递得不够好,我无法得出最佳答案。因此,我在下面发布了一个测试驱动程序,用于评估 iat2()
OP 提出的任何细节的精度。
存在 3 个陷阱。 1)当答案是+180度时,OP似乎想要-128 BAM。但是 atan2(-1, 0.0)
得出 +pi。这种符号反转可能是个问题。注意:atan2(-1, -0.0)
--> -pi。 Ref . 2) 当答案略小于 +180 度时,根据 iat2()
的详细信息,整数 BAM 结果为 +128,倾向于回绕到 -128。 atan2()
结果仅小于 +pi 或 +128 BAM。这个边缘条件需要审查 inOP 的最终代码。 3) (x=0,y=0) 情况需要特殊处理。八分圆选择代码找到它。
signed char atanSC(signed char x)
的代码,如果需要快速,可以使用一些 if()
和一个 64字节查找表。 (假设一个 8 位有符号字符)。 iat2()
中可以使用同一张表。
.
#include <stdio.h>
#include <stdlib.h>
// -x > -y >= 0, so divide by 0 not possible
static signed char iat2(signed char y, signed char x) {
// printf("x=%4d y=%4d\n", x, y); fflush(stdout);
return ((y*32+(x/2))/x)*2; // 3.39 mxdiff
// return ((y*64+(x/2))/x); // 3.65 mxdiff
// return (y*64)/x; // 3.88 mxdiff
}
signed char iatan2sc(signed char y, signed char x) {
// determine octant
if (y >= 0) { // oct 0,1,2,3
if (x >= 0) { // oct 0,1
if (x > y) {
return iat2(-y, -x)/2 + 0*32;
} else {
if (y == 0) return 0; // (x=0,y=0)
return -iat2(-x, -y)/2 + 2*32;
}
} else { // oct 2,3
// if (-x <= y) {
if (x >= -y) {
return iat2(x, -y)/2 + 2*32;
} else {
return -iat2(-y, x)/2 + 4*32;
}
}
} else { // oct 4,5,6,7
if (x < 0) { // oct 4,5
// if (-x > -y) {
if (x < y) {
return iat2(y, x)/2 + -4*32;
} else {
return -iat2(x, y)/2 + -2*32;
}
} else { // oct 6,7
// if (x <= -y) {
if (-x >= y) {
return iat2(-x, y)/2 + -2*32;
} else {
return -iat2(y, -x)/2 + -0*32;
}
}
}
}
#include <math.h>
static void test_iatan2sc(signed char y, signed char x) {
static int mn=INT_MAX;
static int mx=INT_MIN;
static double mxdiff = 0;
signed char i = iatan2sc(y,x);
static const double Pi = 3.1415926535897932384626433832795;
double a = atan2(y ? y : -0.0, x) * 256/(2*Pi);
if (i < mn) {
mn = i;
printf ("x=%4d,y=%4d --> %4d %f, mn %d mx %d mxdiff %f\n",
x,y,i,a,mn,mx,mxdiff);
}
if (i > mx) {
mx = i;
printf ("x=%4d,y=%4d --> %4d %f, mn %d mx %d mxdiff %f\n",
x,y,i,a,mn,mx,mxdiff);
}
double diff = fabs(i - a);
if (diff > 128) diff = fabs(diff - 256);
if (diff > mxdiff) {
mxdiff = diff;
printf ("x=%4d,y=%4d --> %4d %f, mn %d mx %d mxdiff %f\n",
x,y,i,a,mn,mx,mxdiff);
}
}
int main(void) {
int x,y;
int n = 127;
for (y = -n-1; y <= n; y++) {
for (x = -n-1; x <= n; x++) {
test_iatan2sc(y,x);
}
}
puts("Done");
return 0;
}
顺便说一句:一个有趣的问题。
关于c++ - 带符号的 Char ATAN2 和 ATAN 近似值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26201084/
我必须做一些需要使用三角函数的计算,尤其是 atan一。代码将在 Atmega328p 上运行,为了效率,我不能使用 float s:我使用的是定点数。因此,我不能使用标准 atan功能。 我有一个函
我一直在谷歌上搜索这个问题的解决方案。我见过多种计算任何 -1 #include double my_atan(double x) { return x - (x*x*x)/3 + (x*
我正在用 JavaScript 编写我的第一个项目。据我了解,Math.atan() 返回一个数字(以弧度表示的 Angular )。但不知何故,它返回了 Nan。 使用console.log(),我
我遇到 Math.atan 返回与输入相同的值的问题。 public double inchToMOA( double in, double range){ double rangeI
这里是一位非常初级的程序员(两周前开始),我目前在使用 Math.atan 时遇到问题。我目前使用 Eclipse IDE,并且一直在尝试找出如何对三角形执行 tan^-1,但目前不起作用。我在控制台
下面的代码演示了 atan 的计算时间可以有很大的不同: #include #include #include #include #include #include double get_
我有以下小程序,它在我的大型项目中重现了一个触发错误: #define _USE_MATH_DEFINES #include #include #define R2D(trig_fn, val)
我在我的代码中得到了这个函数: -(void)printAngle { int width = p2_t.x-cp1_t.x; int height = p2_t.y-cp1_t.y;
我有个小问题我不知道如何在 cobol 中转换我的 ATAN/ASIN/ACOS 函数这是代码: ACCEPT A
我试图在点的 Angular 之间做一些比较,但很快我遇到了一些奇怪的结果。 在这个例子中,我尝试旋转线条,使它们指向中心,但线条的 Angular 似乎超过了它们应该很快的 Angular 。然后,
我正在尝试计算一个实体观看另一个实体时必须观察的角度。 l是第一个实体的位置。 o是另一个实体的位置。 每个实体在 3D 空间中都有一个 3D X、Y 和 Z 坐标。 我目前使用 double ang
这个问题已经有答案了: What is the difference between atan and atan2 in C++? (11 个回答) 已关闭 6 年前。 我有一个问题。 atan 和有
我如何将我的 atan 函数放入 atan2 中?例如 float myAtan2(double a, double b) { float atan2val = //calculate ata
Java Math.atan() 函数是否已知有任何问题?我在我的代码中使用它,由于一些我无法解决的奇怪原因,该函数将在 45 度运动时返回 0,跳转到 45 并保持在 45 直到它达到 63.4 度
我在一些基本的触发方面遇到了一些麻烦。我正在做一些数学作业,我终于厌倦了将直角坐标转换为极坐标,反之亦然,所以我决定编写一个小 Python 程序来帮助我进行转换。但是, Math.atan() 给我
我的公式f=arctan(ImZ/ReZ) 有两种选择: 选项 1 (atan): ImZ=-4.593172163003 ImR=-4.297336384845 >>> z=y/x >>> f1=m
atan 和 atan2 都是反正切函数,返回的都是弧度 对于两点形成的直线,两点分别是 point(x1,y1) 和 point(x2,y2),其斜率对应角度的计算方法可以是:
我有一个 2D 侧视射击游戏,我需要一些新的视角。我目前正在研究瞄准,并且它部分有效: Guzzle 速度已知,重力已知,并且到目标的 x,y 距离也已知。使用 SE 和维基百科上的各种来源,我提出了
我在java编程中使用半正矢公式(使用eclipse)。我的问题是在等式的末尾,我收到一个错误(atan 带下划线),指出“方法 atan(double) 对于 Math 类型未定义”。 我不知道出了
所以我想获得2点之间的度数,但是当我希望它返回180时,它返回0...0、90和270确实有效,但是当它180时它返回0..这是我的代码: Location loc1 = new Location(B
我是一名优秀的程序员,十分优秀!