在SciPy中使用16384.0 * floor(v / 16384.0)的说明

时间:2014-01-10 18:19:11

标签: c scipy scientific-computing

当我找到这个函数(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))会产生无效结果。我冒昧地说这是用来平息这个,但我不知道它是如何以及为什么这样。

3 个答案:

答案 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的断言:

  1. 检查if (v != floor(v))检查v是否为整数,然后继续。
  2. 在其他功能调用reflect_jy之前,v使用以下方式转为正值

    if (v < 0) {
        v = -v;
        sign = -1;
    }
    

    然后是

    if (sign == -1) {
        if (!reflect_jy(&cy_j, v)) {
            # Function calls, see source.
        }
    }
    
  3. 因此,如果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。