当我找到这个函数(1)
时,我正在研究scipy源代码static int
reflect_jy(npy_cdouble *jy, double v)
{
/* NB: Y_v may be huge near negative integers -- so handle exact
* integers carefully
*/
int i;
if (v != floor(v))
return 0;
i = v - 16384.0 * floor(v / 16384.0);
if (i & 1) {
jy->real = -jy->real;
jy->imag = -jy->imag;
}
return 1;
}
我对i = v - 16384.0 * floor(v / 16384.0)
行感到困惑。我知道16384 = 16 * 1024,但我想知道为什么在目前的代码中使用它。
该代码用于贝塞尔函数的计算,特别是Y_v(z)
。当v
为负且接近整数时,标准反射公式(包括cos(pi * nu)和sin(pi * nu))会产生无效结果。我冒昧地说这是用来平息这个,但我不知道它是如何以及为什么这样。
答案 0 :(得分:6)
代码想要检查已知为整数的浮点数的奇偶校验。
实际上,重要的是处理与任意顺序情况分开的整数顺序情况,因为sin / cos反射公式最终会接近0 * inf情况,这会破坏数值精度。
直接投射(int)v
可能会溢出,因此在i = v; if (i & 1)
之前会使用除偶数的余数。
为什么选择16384.0而不是2.0?我想,重点是减少浮点运算中精度损失的结果 - 浮点数的奇偶校验可能来自尾数中的最后一位数。这个技巧来自其他有点旧代码(来自80年代),并且可能是用非IEEE fp算法编写的;假设IEEE fp,我想有更好的方法来做到这一点。
答案 1 :(得分:1)
我也不确定,但到目前为止我的调查结果都是我的答案,也许他们会帮助其他人找到解决方案。
关于v
的断言:
if (v != floor(v))
检查v
是否为整数,然后继续。在其他功能调用reflect_jy
之前,v
使用以下方式转为正值
if (v < 0) {
v = -v;
sign = -1;
}
然后是
if (sign == -1) {
if (!reflect_jy(&cy_j, v)) {
# Function calls, see source.
}
}
因此,如果v
到达i = v - 16384.0 * floor(v / 16384.0)
行,我们就知道它是一个正整数。
以下是我用来帮助了解数据的表格:
i = v - 2**14 * floor(v/2**14)
===== ===== ===== ==============
0 = 0 - 16384 * 0
1 = 1 - 16384 * 0
2 = 2 - 16384 * 0
3 = 3 - 16384 * 0
4 = 4 - 16384 * 0
5 = 5 - 16384 * 0
6 = 6 - 16384 * 0
7 = 7 - 16384 * 0
8 = 8 - 16384 * 0
9 = 9 - 16384 * 0
10 = 10 - 16384 * 0
11 = 11 - 16384 * 0
16372 = 16372 - 16384 * 0
16373 = 16373 - 16384 * 0
16374 = 16374 - 16384 * 0
16375 = 16375 - 16384 * 0
16376 = 16376 - 16384 * 0
16377 = 16377 - 16384 * 0
16378 = 16378 - 16384 * 0
16379 = 16379 - 16384 * 0
16380 = 16380 - 16384 * 0
16381 = 16381 - 16384 * 0
16382 = 16382 - 16384 * 0
16383 = 16383 - 16384 * 0
i = v - 2**14 * floor(v/2**14)
===== ===== ===== ==============
0 = 16384 - 16384 * 1
1 = 16385 - 16384 * 1
2 = 16386 - 16384 * 1
3 = 16387 - 16384 * 1
4 = 16388 - 16384 * 1
5 = 16389 - 16384 * 1
6 = 16390 - 16384 * 1
7 = 16391 - 16384 * 1
8 = 16392 - 16384 * 1
9 = 16393 - 16384 * 1
10 = 16394 - 16384 * 1
11 = 16395 - 16384 * 1
16372 = 32756 - 16384 * 1
16373 = 32757 - 16384 * 1
16374 = 32758 - 16384 * 1
16375 = 32759 - 16384 * 1
16376 = 32760 - 16384 * 1
16377 = 32761 - 16384 * 1
16378 = 32762 - 16384 * 1
16379 = 32763 - 16384 * 1
16380 = 32764 - 16384 * 1
16381 = 32765 - 16384 * 1
16382 = 32766 - 16384 * 1
16383 = 32767 - 16384 * 1
i = v - 2**14 * floor(v/2**14)
===== ===== ===== ==============
0 = 32768 - 16384 * 2
1 = 32769 - 16384 * 2
2 = 32770 - 16384 * 2
3 = 32771 - 16384 * 2
4 = 32772 - 16384 * 2
5 = 32773 - 16384 * 2
6 = 32774 - 16384 * 2
7 = 32775 - 16384 * 2
8 = 32776 - 16384 * 2
9 = 32777 - 16384 * 2
10 = 32778 - 16384 * 2
11 = 32779 - 16384 * 2
16372 = 49140 - 16384 * 2
16373 = 49141 - 16384 * 2
16374 = 49142 - 16384 * 2
16375 = 49143 - 16384 * 2
16376 = 49144 - 16384 * 2
16377 = 49145 - 16384 * 2
16378 = 49146 - 16384 * 2
16379 = 49147 - 16384 * 2
16380 = 49148 - 16384 * 2
16381 = 49149 - 16384 * 2
16382 = 49150 - 16384 * 2
16383 = 49151 - 16384 * 2
i = v - 2**14 * floor(v/2**14)
===== ===== ===== ==============
0 = 49152 - 16384 * 3
1 = 49153 - 16384 * 3
2 = 49154 - 16384 * 3
3 = 49155 - 16384 * 3
4 = 49156 - 16384 * 3
5 = 49157 - 16384 * 3
6 = 49158 - 16384 * 3
7 = 49159 - 16384 * 3
8 = 49160 - 16384 * 3
9 = 49161 - 16384 * 3
10 = 49162 - 16384 * 3
11 = 49163 - 16384 * 3
16372 = 65524 - 16384 * 3
16373 = 65525 - 16384 * 3
16374 = 65526 - 16384 * 3
16375 = 65527 - 16384 * 3
16376 = 65528 - 16384 * 3
16377 = 65529 - 16384 * 3
16378 = 65530 - 16384 * 3
16379 = 65531 - 16384 * 3
16380 = 65532 - 16384 * 3
16381 = 65533 - 16384 * 3
16382 = 65534 - 16384 * 3
16383 = 65535 - 16384 * 3
i = v - 2**14 * floor(v/2**14)
===== ===== ===== ==============
0 = 65536 - 16384 * 4
1 = 65537 - 16384 * 4
2 = 65538 - 16384 * 4
3 = 65539 - 16384 * 4
4 = 65540 - 16384 * 4
5 = 65541 - 16384 * 4
6 = 65542 - 16384 * 4
7 = 65543 - 16384 * 4
8 = 65544 - 16384 * 4
9 = 65545 - 16384 * 4
10 = 65546 - 16384 * 4
11 = 65547 - 16384 * 4
这似乎将i
限制在范围0&lt; = i&lt; 2 ** 14 = 16384。
然后,if(i & 1)
很简单,如果i
是奇数,则返回true,偶数时返回false。
答案 2 :(得分:1)
这是关于保持double
变量的精度。
一次一步:
i = v - 16384.0 * floor(v / 16384.0);
首先计算表达式v/16384.0
表达式16384是我们将要探索的精度限制。
接下来,floor
函数将应用于v/16384.0
的结果。
结果是将除法截断为整数,如整数除法,但具有浮点。
将整数乘以16384.0,将变量v
转换为可被16384整除的最近整数。
当除以16384时,最后的减法产生余数部分。
任何小于1/16384的值都将被截断并且不予考虑。因此v
的精度限制为1/16384。