Javascript 计算负数的立方根
简而言之 三,√(-8)=-8 1/3 但当我测试它时,它会输出Javascript 计算负数的立方根,javascript,math,Javascript,Math,简而言之 三,√(-8)=-8 1/3 但当我测试它时,它会输出 NaN 为什么??它是一个bug还是一开始就被认为是这样的?我正在使用JavaScript绘制图形,但这会弄乱图形。没有错误;你把一个负数提升到分数次幂;因此,南 谷歌最受欢迎的是它的解释很好。它说对于实数(无论如何不是复数),一个负数提升到分数次幂可能不是实数。最简单的例子可能是 -4^(1/2) 基本上是计算-4的平方根。尽管-8的立方根确实有实解,但我认为大多数软件库发现,不做所有的复数运算,只在虚部不为零时返回NaN更有
NaN
为什么??它是一个bug还是一开始就被认为是这样的?我正在使用JavaScript绘制图形,但这会弄乱图形。没有错误;你把一个负数提升到分数次幂;因此,南 谷歌最受欢迎的是它的解释很好。它说对于实数(无论如何不是复数),一个负数提升到分数次幂可能不是实数。最简单的例子可能是 -4^(1/2) 基本上是计算-4的平方根。尽管-8的立方根确实有实解,但我认为大多数软件库发现,不做所有的复数运算,只在虚部不为零时返回NaN更有效,否则会给出很好的实解 编辑 只是要明确指出,
NaN
是预期结果。它说:
如果x,您可以使用此代码段来计算它。它也适用于其他电源,例如
1/4
,1/5
等
function nthroot(x, n) {
try {
var negate = n % 2 == 1 && x < 0;
if(negate)
x = -x;
var possible = Math.pow(x, 1 / n);
n = Math.pow(possible, n);
if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
return negate ? -possible : possible;
} catch(e){}
}
nthroot(-8, 3);
更新
要查找基于整数的立方根,可以使用以下函数,其灵感来自:
它首先假设收敛到最接近的整数
a
,对于这个整数a^3我喜欢其他答案,但是覆盖Math.pow
怎么样,这样它就可以处理负数的所有第n个根:
//keep the original method for proxying
Math.pow_ = Math.pow;
//redefine the method
Math.pow = function(_base, _exponent) {
if (_base < 0) {
if (Math.abs(_exponent) < 1) {
//we're calculating nth root of _base, where n === 1/_exponent
if (1 / _exponent % 2 === 0) {
//nth root of a negative number is imaginary when n is even, we could return
//a string like "123i" but this would completely mess up further computation
return NaN;
}/*else if (1 / _exponent % 2 !== 0)*/
//nth root of a negative number when n is odd
return -Math.pow_(Math.abs(_base), _exponent);
}
}/*else if (_base >=0)*/
//run the original method, nothing will go wrong
return Math.pow_(_base, _exponent);
};
//保留代理的原始方法
Math.pow=Math.pow;
//重新定义方法
Math.pow=函数(_基,_指数){
如果(_base<0){
if(数学绝对值(_指数)<1){
//我们正在计算_基的n根,其中n==1/_指数
如果(1/_指数%2==0){
//负数的n根是虚数,当n为偶数时,我们可以返回
//类似于“123i”的字符串,但这将完全扰乱进一步的计算
返回NaN;
}/*否则如果(1/_指数%2!==0)*/
//n为奇数时负数的n根
return-Math.pow(Math.abs(_base),_指数);
}
}/*如果(_base>=0),则为else*/
//运行原始方法,不会出错
返回Math.pow(基数,指数);
};
对于一些测试用例,如果你发现一个bug,请给我一个提示 两个关键问题:
从数学上讲,负数有多个立方根:-2,但也有两个复数根(请参阅)
Javascript的Math
对象(以及大多数其他标准数学库)不会执行负数的分数幂运算。它会在函数接收分数幂之前将分数幂转换为浮点,因此您要求函数计算负数的浮点幂,这可能有也可能没有实数解。因此,它做了实事求是的事情,拒绝尝试计算这样的价值
如果你想得到正确的答案,你需要决定你想要的数学正确程度,并将这些规则写入pow
的非标准实现中
所有库函数都受到限制,以避免过多的计算时间和不必要的复杂性 它在Chrome控制台中工作
function cubeRoot(number) {
var num = number;
var temp = 1;
var inverse = 1 / 3;
if (num < 0) {
num = -num;
temp = -1;
}
var res = Math.pow(num, inverse);
var acc = res - Math.floor(res);
if (acc <= 0.00001)
res = Math.floor(res);
else if (acc >= 0.99999)
res = Math.ceil(res);
return (temp * res);
}
cubeRoot(-64) // -4
cubeRoot(64) // 4
函数cubeRoot(编号){
var num=数字;
var-temp=1;
var逆=1/3;
if(num<0){
num=-num;
温度=-1;
}
var res=数学功率(num,逆);
var acc=res-数学地板(res);
如果(acc=0.99999)
res=数学单元(res);
返回(临时*res);
}
cubeRoot(-64)/-4
cubeRoot(64)//4
//除了符号之外,负数的立方根不是与正数相同吗
Math.cubeRoot= function(n, r){
var sign= (n<0)? -1: 1;
return sign*Math.pow(Math.abs(n), 1/3);
}
Math.cubeRoot(-8)
/* returned value: (Number)
-2
*/
Math.cubeRoot=函数(n,r){
var sign=(n所以我看到了一系列围绕Math.pow(…)
的方法,这很酷,但基于赏金的措辞,我提出了一种稍微不同的方法
求解根有几种计算近似方法,有些方法比其他方法更快。最终,停止点会下降到所需的精度(取决于您/正在解决的问题)
我不打算详细解释数学,但以下是通过目标测试(赏金测试-由于问题标题,还增加了负范围)的立方根近似的实现。循环中的每个迭代(参见while(math.abs(xi-xi0)>precision)
每个方法中的循环)获取更接近所需精度的一步。一旦达到精度,将对数字应用格式,使其与从迭代中导出的计算一样精确
var precision = 0.0000000000001;
function test_cuberoot_fn(fn) {
var tested = 0,
failed = 0;
for (var i = -100; i < 100; i++) {
var root = fn(i*i*i);
if (i !== root) {
console.log(i, root);
failed++;
}
tested++;
}
if (failed) {
console.log("failed %d / %d", failed, tested);
}else{
console.log("Passed test");
}
}
test_cuberoot_fn(newtonMethod);
test_cuberoot_fn(halleysMethod);
哈雷近似实现
请注意,哈雷近似法求解立方体的步骤更快,因此计算速度比牛顿近似法更快
function halleysMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = xi*((xi*xi*xi + 2*cube)/(2*xi*xi*xi+cube));
}
return Number(xi.toPrecision(12));
}
首先,ES6中现在有一个Math.cbrt函数
在我在谷歌chrome上的测试中,它的运行速度几乎是Math.pow的两倍。有趣的是,我不得不将结果相加,否则chrome在优化pow函数方面做得更好
//do a performance test on the cube root function from es6
var start=0, end=0, k=0;
start = performance.now();
k=0;
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
//k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
//k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
只想强调ES6中有一个函数,所以你可以这样做(检查支持)
Math.cbrt(-8)
将返回您的-2
这适用于负数和负指数:
函数n根(x=0,r=1){
if(x<0){
if(r%2==1)返回-nthRoot(-x,r)
if(r%2==-1)返回-1/n根(-x,-r)
}
返回x**(1/r)
}
示例:
nthRoot( 16, 2) 4
nthRoot( 16, -2) 0.25
nthRoot(-16, 2) NaN
nthRoot(-16, -2) NaN
nthRoot( 27, 3) 3
nthRoot( 27, -3) 0.3333333333333333
nthRoot(-27, 3) -3
nthRoot(-27, -3) -0.3333333333333333
那我怎么做3呢√(-8)
不做8^(1/3)
?您可以切换到Wolfram Alpha,它比JavaScript更擅长处理这些事情:)认真地说,JavaScript只是简单地解决了这些问题,并对它们说NaN,因为它们通常是复数,JavaScript本机不支持它们
function newtonMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = (1/3)*((cube/(xi*xi))+2*xi);
}
return Number(xi.toPrecision(12));
}
function halleysMethod(cube){
if(cube == 0){//only John Skeet and Chuck Norris
return 0; //can divide by zero, we'll have
} //to settle for check and return
var xi = 1;
var xi0 = -1;
while(Math.abs(xi-xi0)>precision){//precision = 0.0000000000001
xi0=xi;
xi = xi*((xi*xi*xi + 2*cube)/(2*xi*xi*xi+cube));
}
return Number(xi.toPrecision(12));
}
//do a performance test on the cube root function from es6
var start=0, end=0, k=0;
start = performance.now();
k=0;
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
//k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
//k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.cbrt(i);
k+=j;
}
end = performance.now();
console.log("cbrt took:" + (end-start),k);
k=0;
start = performance.now();
for (var i=0.0; i<10000000.0; i+=1.0)
{
var j = Math.pow(i,0.33333333);
k+=j;
}
end = performance.now();
console.log("pow took:" + (end-start),k);
cbrt took:468.28200000163633 0
pow took:77.21999999921536 0
cbrt took:546.8039999977918 1615825909.5248165
pow took:869.1149999940535 1615825826.7510242
nthRoot( 16, 2) 4
nthRoot( 16, -2) 0.25
nthRoot(-16, 2) NaN
nthRoot(-16, -2) NaN
nthRoot( 27, 3) 3
nthRoot( 27, -3) 0.3333333333333333
nthRoot(-27, 3) -3
nthRoot(-27, -3) -0.3333333333333333