查找数字的第n个根的最快方法

时间:2017-02-14 07:20:21

标签: java math

问题是找到数字的第n个根,如果根是一个整数i需要打印它,否则我将打印-1。我曾经使用过这种方法,但我得到了。有没有比我实施的更快的方法?

这是我的代码:

public class Sqrt {
  public static double nthroot(int n, double x)//calculates root
  {
    return Math.pow(x,1./n);
  }

  public static void main(String[] args) throws IOException 
  {
    BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
    int t,n,m;
    double x;
    String[] y;
    t=Integer.parseInt(br.readLine());
    while(t-->0)//test cases
    {
      y=br.readLine().split(" ");//to get number and the exp
      n=Integer.parseInt(y[1]);//the exp
      m=Integer.parseInt(y[0]);//the number
      x=nthroot(m,n);
      x=BigDecimal.valueOf(x)
                            .setScale(5, RoundingMode.HALF_UP)
                            .doubleValue();//to set precision upto 5 decimal places
      if(x==(int)x)// **checks whether the root obtained is integer or not**
      {
        System.out.println((int)x);
      }
      else
      {  
        System.out.println(-1);
      }
    }
  }
}

1 个答案:

答案 0 :(得分:1)

最快(针对许多查​​询进行了优化)将为所有非平凡根(exp = 2,3,4,5,...)创建 SoE (Eratosthenes筛选)表。

x^(1/2)的表格为(10^9)^(1/2) = 31622整数。对于x^1/3,它只是1000个整数,并且数字随指数递减...您可以使用整数位宽度除法来获取表格大小而不是pow ...

例如x^(1/3) SoE 就像这样在C ++中:

const bits=32;  // binary bits count of 10^9
int e = 3;      // rooth exponent
int n =1<<(1+bits/e); // table size
int *soe=new int [n+1];
int x;
for (x=0;x<=n;x++) soe[x]=x*x*x;

现在soe[]保存{ 0,1,27,64,125,...},它们都是整数立方根。所以对于立方根上的任何查询,你只需要搜索soe表,如果找到完全匹配,则返回soe中的索引,否则返回-1。

你可以为每个指数构建一个soe表(1除外),例如soe[exp-2][] ......

如果你想在没有 SoE 的情况下构建它,那么只使用整数二进制搜索:

[Edit1]这里简单的32位C ++(抱歉我不用JAVA编写代码)示例:

//---------------------------------------------------------------------------
//typedef uint32_t DWORD;           // uncomment this if no DWORD type is present
//typedef uint16_t WORD;            // uncomment this if no WORD type is present
const int _nroot_maxe=30;           // max exponent
DWORD *soe[_nroot_maxe+3]={NULL};   // soe[][]
DWORD soen[_nroot_maxe+3];          // soe[e] size
DWORD soem[_nroot_maxe+3];          // soe[e] index MSB mask
//---------------------------------------------------------------------------
void mul(DWORD &h,DWORD &l,DWORD x,DWORD y) // (h,l) =  x * y
    {                                       //  64   = 32 * 32 bits
    const int _h=1; // this is platform dependent MSW/LSW order !!!
    const int _l=0;
    union _u
        {
        DWORD u32;
        WORD u16[2];
        }u;
    DWORD al,ah,bl,bh;
    DWORD c0,c1,c2,c3;
    // separate 2^16 base digits
    u.u32=x; al=u.u16[_l]; ah=u.u16[_h];
    u.u32=y; bl=u.u16[_l]; bh=u.u16[_h];
    // multiplication (al+ah<<1)*(bl+bh<<1) = al*bl + al*bh<<1 + ah*bl<<1 + ah*bh<<2
    c0=(al*bl);        
    c1=(al*bh)+(ah*bl);
    c2=(ah*bh);        
    c3= 0;
    // propagate 2^16 overflows (backward to avoid overflow)
    c3+=c2>>16; c2&=0x0000FFFF; 
    c2+=c1>>16; c1&=0x0000FFFF; 
    c1+=c0>>16; c0&=0x0000FFFF;
    // propagate 2^16 overflows (normaly to recover from secondary overflow)
    c2+=c1>>16; c1&=0x0000FFFF;
    c3+=c2>>16; c2&=0x0000FFFF;
    // (c3,c2,c1,c0) -> (h,l)
    u.u16[_l]=c0; u.u16[_h]=c1; l=u.u32;
    u.u16[_l]=c2; u.u16[_h]=c3; h=u.u32;
    }
//---------------------------------------------------------------------------
void nroot_init()   // init SoE tables for nroot
    {
    DWORD i,e,n,m,h,l;
    // compute table sizes
    soen[0]=0; soem[0]=0;
    soen[1]=0; soem[1]=0;
    for (n=0,e=2;e<=_nroot_maxe;e++)
        {
        i=1<<((31+e-1)/e);
        soen[e]=i;
        n+=i;
        }
    // allocate memory and set pointers
    soe[0]=new DWORD[n];
    for (e=1;e<=_nroot_maxe;e++) soe[e]=soe[e-1]+soen[e-1];
    // soe
    for (e=2,i=0;i<soen[e];i++) soe[e][i]=i*i;
    for (e=3;e<=_nroot_maxe;e++)
     for (i=0;i<soen[e];i++)
        {
        mul(h,l,i,soe[e-1][i]);     // 32bit * 32bit = 64bit
        if (!h) soe[e][i]=l;        // if no 32bit overflow store result
         else soen[e]=i;            // stop otherwise
        }
    // compute bin search index masks
    for (m=0x80000000,e=2;e<=_nroot_maxe;e++)
        {
        while (m>=soen[e]) m>>=1; m<<=1;
        soem[e]=m;
        }
    }
//---------------------------------------------------------------------------
void nroot_exit()   // release SoE tables (free memory)
    {
    // release memory
    if (soe[0]!=NULL) delete[] soe[0];
    for (DWORD e=0;e<=_nroot_maxe;e++)
        {
        soe[e]=NULL;
        soen[e]=0;
        soem[e]=0;
        }
    }
//---------------------------------------------------------------------------
int nroot(DWORD x,DWORD e)  // e-th root of x or -1 if not integer result
    {
    // special cases
    if (e==0) return -1;
    if (e==1) return x;
    if (e>_nroot_maxe) return -1;
    // init if needed
    if (soe[0]==NULL) nroot_init();
    // binary search
    DWORD m,i;
    for (i=0,m=soem[e];m;m>>=1)
        {
        i|=m;
        if ((i>=soen[e])||(soe[e][i]>x)) i^=m;
        }
    if (soe[e][i]==x) return i;
    return -1;
    }
//---------------------------------------------------------------------------

对于那些没有DWORDWORD取消注释typedef或更改为平台上无符号32位和16位整数的人...同时将_h,_l常量设置为匹配您的平台。

即使这样也可以加快......只要意识到对于更高的指数,可能只有0,1,2,3 ... 0,1个指数......

必须只调用一次init函数。在我的设置上,~0.187ms花了几乎可以忽略不计。对所有1000000000第5根进行测试需要~16sec