任何人都可以帮我找到一个有效的代码来找到10个电源x吗?
private int power(int base, int exp)
{
int result = 1;
while (exp != 0)
{
if ((exp & 1) == 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
来自here的代码来源,但我正在寻找一种输入可能是3.14(双倍)的方法。我也不能使用任何库函数。功率可以是实数。因此,我们可以通过Squaring的Exponentiation找到一个简单的整数算法。
答案 0 :(得分:7)
答案 1 :(得分:1)
这是来自Java pow
实现的StrictMath
方法。从技术上讲,StrictMath
有利于准确性而不是性能,但实际上它非常快,因为它在Java中随处可见我复制并格式化了pow
函数所需的源代码: ):
public class YourMathClass {
public static double pow(double x, double y) {
// Special cases first.
if (y == 0)
return 1;
if (y == 1)
return x;
if (y == -1)
return 1 / x;
if (x != x || y != y)
return Double.NaN;
// When x < 0, yisint tells if y is not an integer (0), even(1),
// or odd (2).
int yisint = 0;
if (x < 0 && floor(y) == y)
yisint = (y % 2 == 0) ? 2 : 1;
double ax = abs(x);
double ay = abs(y);
// More special cases, of y.
if (ay == Double.POSITIVE_INFINITY) {
if (ax == 1)
return Double.NaN;
if (ax > 1)
return y > 0 ? y : 0;
return y < 0 ? -y : 0;
}
if (y == 2)
return x * x;
if (y == 0.5)
return sqrt(x);
// More special cases, of x.
if (x == 0 || ax == Double.POSITIVE_INFINITY || ax == 1) {
if (y < 0)
ax = 1 / ax;
if (x < 0) {
if (x == -1 && yisint == 0)
ax = Double.NaN;
else if (yisint == 1)
ax = -ax;
}
return ax;
}
if (x < 0 && yisint == 0)
return Double.NaN;
// Now we can start!
double t;
double t1;
double t2;
double u;
double v;
double w;
if (ay > TWO_31) {
if (ay > TWO_64) // Automatic over/underflow.
return ((ax < 1) ? y < 0 : y > 0) ? Double.POSITIVE_INFINITY : 0;
// Over/underflow if x is not close to one.
if (ax < 0.9999995231628418)
return y < 0 ? Double.POSITIVE_INFINITY : 0;
if (ax >= 1.0000009536743164)
return y > 0 ? Double.POSITIVE_INFINITY : 0;
// Now |1-x| is <= 2**-20, sufficient to compute
// log(x) by x-x^2/2+x^3/3-x^4/4.
t = x - 1;
w = t * t * (0.5 - t * (1 / 3.0 - t * 0.25));
u = INV_LN2_H * t;
v = t * INV_LN2_L - w * INV_LN2;
t1 = (float) (u + v);
t2 = v - (t1 - u);
} else {
long bits = Double.doubleToLongBits(ax);
int exp = (int) (bits >> 52);
if (exp == 0) // Subnormal x.
{
ax *= TWO_54;
bits = Double.doubleToLongBits(ax);
exp = (int) (bits >> 52) - 54;
}
exp -= 1023; // Unbias exponent.
ax = Double.longBitsToDouble((bits & 0x000fffffffffffffL) | 0x3ff0000000000000L);
boolean k;
if (ax < SQRT_1_5) // |x|<sqrt(3/2).
k = false;
else if (ax < SQRT_3) // |x|<sqrt(3).
k = true;
else {
k = false;
ax *= 0.5;
exp++;
}
// Compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5).
u = ax - (k ? 1.5 : 1);
v = 1 / (ax + (k ? 1.5 : 1));
double s = u * v;
double s_h = (float) s;
double t_h = (float) (ax + (k ? 1.5 : 1));
double t_l = ax - (t_h - (k ? 1.5 : 1));
double s_l = v * ((u - s_h * t_h) - s_h * t_l);
// Compute log(ax).
double s2 = s * s;
double r = s_l * (s_h + s) + s2 * s2 * (L1 + s2 * (L2 + s2 * (L3 + s2 * (L4 + s2 * (L5 + s2 * L6)))));
s2 = s_h * s_h;
t_h = (float) (3.0 + s2 + r);
t_l = r - (t_h - 3.0 - s2);
// u+v = s*(1+...).
u = s_h * t_h;
v = s_l * t_h + t_l * s;
// 2/(3log2)*(s+...).
double p_h = (float) (u + v);
double p_l = v - (p_h - u);
double z_h = CP_H * p_h;
double z_l = CP_L * p_h + p_l * CP + (k ? DP_L : 0);
// log2(ax) = (s+..)*2/(3*log2) = exp + dp_h + z_h + z_l.
t = exp;
t1 = (float) (z_h + z_l + (k ? DP_H : 0) + t);
t2 = z_l - (t1 - t - (k ? DP_H : 0) - z_h);
}
// Split up y into y1+y2 and compute (y1+y2)*(t1+t2).
boolean negative = x < 0 && yisint == 1;
double y1 = (float) y;
double p_l = (y - y1) * t1 + y * t2;
double p_h = y1 * t1;
double z = p_l + p_h;
if (z >= 1024) // Detect overflow.
{
if (z > 1024 || p_l + OVT > z - p_h)
return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
} else if (z <= -1075) // Detect underflow.
{
if (z < -1075 || p_l <= z - p_h)
return negative ? -0.0 : 0;
}
// Compute 2**(p_h+p_l).
int n = round((float) z);
p_h -= n;
t = (float) (p_l + p_h);
u = t * LN2_H;
v = (p_l - (t - p_h)) * LN2 + t * LN2_L;
z = u + v;
w = v - (z - u);
t = z * z;
t1 = z - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
double r = (z * t1) / (t1 - 2) - (w + z * w);
z = scale(1 - (r - z), n);
return negative ? -z : z;
}
public static int round(float f) {
return (int) floor(f + 0.5f);
}
public static double floor(double a) {
double x = abs(a);
if (!(x < TWO_52) || (long) a == a)
return a; // No fraction bits; includes NaN and infinity.
if (x < 1)
return a >= 0 ? 0 * a : -1; // Worry about signed zero.
return a < 0 ? (long) a - 1.0 : (long) a; // Cast to long truncates.
}
public static double abs(double d) {
return (d <= 0) ? 0 - d : d;
}
public static double sqrt(double x) {
if (x < 0)
return Double.NaN;
if (x == 0 || !(x < Double.POSITIVE_INFINITY))
return x;
// Normalize x.
long bits = Double.doubleToLongBits(x);
int exp = (int) (bits >> 52);
if (exp == 0) // Subnormal x.
{
x *= TWO_54;
bits = Double.doubleToLongBits(x);
exp = (int) (bits >> 52) - 54;
}
exp -= 1023; // Unbias exponent.
bits = (bits & 0x000fffffffffffffL) | 0x0010000000000000L;
if ((exp & 1) == 1) // Odd exp, double x to make it even.
bits <<= 1;
exp >>= 1;
// Generate sqrt(x) bit by bit.
bits <<= 1;
long q = 0;
long s = 0;
long r = 0x0020000000000000L; // Move r right to left.
while (r != 0) {
long t = s + r;
if (t <= bits) {
s = t + r;
bits -= t;
q += r;
}
bits <<= 1;
r >>= 1;
}
// Use floating add to round correctly.
if (bits != 0)
q += q & 1;
return Double.longBitsToDouble((q >> 1) + ((exp + 1022L) << 52));
}
private static double scale(double x, int n) {
// if (Configuration.DEBUG && abs(n) >= 2048)
// throw new InternalError("Assertion failure");
if (x == 0 || x == Double.NEGATIVE_INFINITY || !(x < Double.POSITIVE_INFINITY) || n == 0)
return x;
long bits = Double.doubleToLongBits(x);
int exp = (int) (bits >> 52) & 0x7ff;
if (exp == 0) // Subnormal x.
{
x *= TWO_54;
exp = ((int) (Double.doubleToLongBits(x) >> 52) & 0x7ff) - 54;
}
exp += n;
if (exp > 0x7fe) // Overflow.
return Double.POSITIVE_INFINITY * x;
if (exp > 0) // Normal.
return Double.longBitsToDouble((bits & 0x800fffffffffffffL) | ((long) exp << 52));
if (exp <= -54)
return 0 * x; // Underflow.
exp += 54; // Subnormal result.
x = Double.longBitsToDouble((bits & 0x800fffffffffffffL) | ((long) exp << 52));
return x * (1 / TWO_54);
}
private static final double TWO_31 = 0x80000000L, // Long bits 0x41e0000000000000L.
TWO_52 = 0x10000000000000L, // Long bits 0x4330000000000000L.
TWO_54 = 0x40000000000000L, // Long bits 0x4350000000000000L.
TWO_64 = 1.8446744073709552e19; // Long bits 0x7fe0000000000000L.
private static final double L1 = 0.5999999999999946, // Long bits 0x3fe3333333333303L.
L2 = 0.4285714285785502, // Long bits 0x3fdb6db6db6fabffL.
L3 = 0.33333332981837743, // Long bits 0x3fd55555518f264dL.
L4 = 0.272728123808534, // Long bits 0x3fd17460a91d4101L.
L5 = 0.23066074577556175, // Long bits 0x3fcd864a93c9db65L.
L6 = 0.20697501780033842, // Long bits 0x3fca7e284a454eefL.
P1 = 0.16666666666666602, // Long bits 0x3fc555555555553eL.
P2 = -2.7777777777015593e-3, // Long bits 0xbf66c16c16bebd93L.
P3 = 6.613756321437934e-5, // Long bits 0x3f11566aaf25de2cL.
P4 = -1.6533902205465252e-6, // Long bits 0xbebbbd41c5d26bf1L.
P5 = 4.1381367970572385e-8, // Long bits 0x3e66376972bea4d0L.
DP_H = 0.5849624872207642, // Long bits 0x3fe2b80340000000L.
DP_L = 1.350039202129749e-8, // Long bits 0x3e4cfdeb43cfd006L.
OVT = 8.008566259537294e-17; // Long bits 0x3c971547652b82feL.
private static final double SQRT_1_5 = 1.224744871391589, // Long bits 0x3ff3988e1409212eL.
SQRT_3 = 1.7320508075688772, // Long bits 0x3ffbb67ae8584caaL.
CP = 0.9617966939259756, // Long bits 0x3feec709dc3a03fdL.
CP_H = 0.9617967009544373, // Long bits 0x3feec709e0000000L.
CP_L = -7.028461650952758e-9, // Long bits 0xbe3e2fe0145b01f5L.
LN2 = 0.6931471805599453, // Long bits 0x3fe62e42fefa39efL.
LN2_H = 0.6931471803691238, // Long bits 0x3fe62e42fee00000L.
LN2_L = 1.9082149292705877e-10, // Long bits 0x3dea39ef35793c76L.
INV_LN2 = 1.4426950408889634, // Long bits 0x3ff71547652b82feL.
INV_LN2_H = 1.4426950216293335, // Long bits 0x3ff7154760000000L.
INV_LN2_L = 1.9259629911266175e-8; // Long bits 0x3e54ae0bf85ddf44L.
}
现在,如果你真的让大规模计算的事情变得非常快(我的意思是成千上万的{{1}}方法调用),我可以建议这样做吗?来自pow
Apache Commons Math类的极速FastMath
函数?
根据您的问题,您不想拥有其他图书馆,因此我将pow
和FastMath
的必要部分复制到一个文件中。它太大了,不能放在StackOverflow上,所以我贴上了PasteAll:
警告:此代码的文件非常庞大。除非您确定使用FastMathLiteralArrays
进行了非常长的计算,否则您不应该使用此文件,因为1)它将使用大量内存而2)它实际上可能更慢如果您打算使用一次或两次。
无论如何,希望这能满足你所有pow
的效率需求:)(我也希望我能获得赏金;)
答案 2 :(得分:1)
在不使用库代码的情况下提供double
输入是没有意义的 - 你要么必须使用库,要么抄袭库代码的来源 - 同样的事情。
但是对于整数运算,不使用库是合理的。
回答你所提出的问题并标题为:
private static int tenToPower(int power) {
int result = 1;
for (int p = 0; p < power; p++)
result *= 10;
return result;
}
由于您的示例代码中的返回类型为int
,因此我假设产生小数结果的负幂超出范围。
答案 3 :(得分:0)
如果你想要真正快速有效的10的功率,并且只需要整数,你可以使用一个表(90年代真正的老技巧),像这样:
static final long powerOfTen[] = {1,10,100,1000,10000, ....} // you get the idea
然后
static long powerOfTen(long input, int power) {
return input * powerOfTen[power];
}
如果你需要更高的精度,你也可以预先计算,但请记住,随着表变大,你赢得越来越少,因为它使用更多的内存/ L1缓存。上面的要点是,由于它的尺寸非常小,静态方法将被内联,并且静态数组非常小,如果适合64字节的L1缓存页面,这意味着性能方面,这将归结为整数乘法寄存器。
答案 4 :(得分:-1)
您可以计算10^x
,而不是计算e^(x*ln(10))
。所以你的问题归结为this one。我可以通过计算Taylor series:
double tenPow(double x) {
// ln(10)
double logTen = 2.3025850929940456840179914546843642076011014886287729;
double sum = 0.;
x *= logTen; // x * ln(10)
double tmp = 1.;
for (double i = 1.; tmp > 0.; i += 1.) {
sum += tmp;
tmp *= x;
tmp /= i;
}
return sum;
}
<强> EDIT1 强>
如评论中所述,此方法对大型x
无效。但我们可以将x
分解为整数和小数部分,因此x = xi + xf
。 e^(xi + xf) = e^xf * e^xi
。可以使用递归求幂有效地计算e^xi
。 e^xf
可以使用泰勒系列计算。
<强> EDIT2 强> 以下是我对此算法的实现:
public static double fastTenPow(double x) {
if (x < 0.) {
return 1. / fastTenPow(-x);
}
int intPart = (int) x;
double fractPart = x - intPart;
return fractTenPow(fractPart) * intTenPow(intPart);
}
private static double intTenPow(int x) { // copied it
double res = 1.;
double base = 10.;
while (x != 0) {
if ((x & 1) == 1) {
res *= base;
}
x >>= 1;
base *= base;
}
return res;
}
private static final double LOG_TEN = 2.3025850929940456840179914546843642076011014886287729;
private static final double EPS = 0.00000000000000001;
private static double fractTenPow(double x) {
double sum = 0.;
x *= LOG_TEN;
double tmp = 1.;
for (double i = 1.; tmp > EPS; i += 1.) {
sum += tmp;
tmp *= x;
tmp /= i;
}
return sum;
}
答案 5 :(得分:-3)
你不能使用简单的递归吗?
public static void main(String[] args) {
System.out.println(power10x(4,1)); //replace ur X value with 4
}
public static int power10x(int a,int val){
if(a==0)
return val;
else
return power10x(a-1,val*10);
}