【问题标题】:How to overcome the NaN and continue the calculation in Javascript - Negative value for radicand of sqrt如何克服 NaN 并在 Javascript 中继续计算 - sqrt radicand 的负值
【发布时间】:2014-10-09 09:18:36
【问题描述】:

我已经为 calculating cylinders 设置了一个 js / three.js 程序,只有两个给定的值。

当给出 volumesurface 时,唯一相当困难的计算发生。从这两个值我需要计算半径或高度。

回忆公式:

体积 V = π·r²·h

表面A = 2·π·r·(r+h)

如果你做数学,你会得到三次公式:0 = r^3 + A/(-2*pi)*r + V/pi

老实说我无法解决,所以我使用了wolframalpha,它给出了半径 r 的结果:

注意:r 有三个公式,这是其中的第一个。见wolframalpha

通过尝试在 Javascript 中实现这个等式,我意识到√(54πV^2 - A^3) 的基数是负数,而 Javascript 正在返回 NaN

这引出了我的问题:我怎样才能克服NaN 并继续计算 - 我应该使用复数,如何?您使用了哪些解决方法?我可以将radicand 乘以*(-1),记住这个值然后考虑吗?

这里有点迷茫,这是我第一次要打败NaN :-)

提前感谢您提供的所有提示、建议、解决方案和代码。


编辑(达到目标):生活在这个地球上的人是否可以在 Javascript 中解决 three equations 并且可以发布他的代码?我通常用谷歌搜索"calculate cylinder by surface and volume",似乎以前没有人这样做过......

【问题讨论】:

  • 三次方程最多可以有三个根。负数或复数半径没有物理意义:您需要一个真实的正根。这表明您要么选择了错误的根,要么您选择的参数没有物理意义。
  • 您正在尝试求解三次方。因此,您最多有三个可能的答案。并非所有可能的答案都是真实的,但您感兴趣的答案会是真实的。得到两个复杂部分的机会是什么?你可以忽略那些不真实的答案吗?至少如果其中一个答案是真实的?
  • 这似乎是一道数学题而不是编程题。
  • @Adam:我不想忽略复杂的部分,我想知道所有 3 个确切的答案。这就是为什么我需要防止 NaN 并将值转换为复数。 Math.sqrt(-9) 应该导致 3*i。由于 Javascript 不包括用复数计算,我正在寻找一个简单的解决方案。此外,应该可以使用复数进行 +-*/ 操作。我想我们可以在这里以某种方式使用向量。我找到了这个在线工具 1728.org/cubic.htm - 他们在这里使用 JS 来计算复数,但他们不处理 NaN 看起来!
  • 相反,他们检查h = (g²/4) + (f³/27) 以确定结果是否复杂,请参阅on their site。嗯,这是求解三次方程的一种方法。然而,我上面的方程的解,让我们说“以直接的方式”仍然没有找到。 @all:这个问题仍然悬而未决。

标签: javascript nan


【解决方案1】:

因此,丢弃负基数并不是最好的解决方案,因为您仍然可能排除有效的实数解决方案,因为第二项中的基数可能会抵消第一项中的虚部。此外,第二和第三根的公式中有 i,所以你不得不在那里处理复数。这些根也不应该被丢弃,因为即使对于具有 3 个实根的三次方,3 个根中的 2 个仍然是使用复数计算的!

处理复数是

  1. JavaScript 无法原生处理,并且
  2. 足够重要,以至于您不想自己实现它。那就是那里。 ma​​th.js 进来了。

阅读 here 以了解 math.js。但是对于这个问题,您只需要了解一种方法即可。 math.js 通过它的math 对象完成它的工作,我们关心的方法是math.eval(expr,scope),它将评估字符串表达式expr 并使用scope 中指定的变量赋值。

因此,首先查看 wolfram 提供的 3 个根:

它们有点笨拙。仔细观察,它们都有一个共同的术语:

该术语是AV 的表达式,因此我们将其移至AV 的函数,称为f

所以用这个词代替我们的新函数f,现在根更易于管理:

那么,让我们开始吧。您只需在项目顶部包含math.js

<script type="text/javascript" language="JavaScript" 
src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/0.26.0/math.min.js"></script>

进入脚本。首先,定义上述f函数:

        var f = function(A, V) {
            var scope = {A: A, V: V};
            var expr = math.eval(
                    '(sqrt(6) pi^(3/2) sqrt(54 pi V^2-A^3)-18 pi^2 V)^(1/3)'
                     ,scope);
            return expr;
        };

请注意:空格隐含意味着相乘,即a b=a*b,并且数字n的立方根等于n^(1/3)

所以f 将使用参数AV 来评估我们的expr 面积和体积。

现在我们可以使用它来定义将生成 3 个根的函数,r1r2r3,给定任何面积 A 和体积 V

        var r1 = function(A, V) {
            var scope = {A: A, V: V, f: f(A, V)};
            var expr = math.eval(
                    'A/(6^(1/3) f)+f/(6^(2/3) pi)'
                    , scope);
            return expr;
        };

        var r2 = function(A, V) {
            var scope = {A: A, V: V, f: f(A, V)};
            var expr = math.eval(
                    '-((1+i sqrt(3)) A)/(2*6^(1/3) f) - ((1-i sqrt(3)) f)/(2*6^(2/3) pi)'
                    , scope);
            return expr;
        };

        var r3 = function(A, V) {
            var scope = {A: A, V: V, f: f(A, V)};
            var expr = math.eval(
                    '-((1-i sqrt(3)) A)/(2*6^(1/3) f) - ((1+i sqrt(3)) f)/(2*6^(2/3) pi)'
                    , scope);
            return expr;
        };

现在,让我们测试一下。使用您提供的link 中的值,假设半径r2,高度h1.5

那么,体积V=pi*r^2 约为18.85,表面积A=2pi*r(r+h) 约为43.982。使用上面定义的方法,我们可以得到根。

请注意,result 是使用给定根计算r^3 + A/(-2*pi)*r + V/pi 的结果,因此如果结果是0,则根计算正确。由于舍入误差,实际值将精确到约 15 位数。

var A, V, r, scope;
A = 43.982, V = 18.85;

        //test r1
        r = r1(A, V);

        scope = {A: A, V: V, r: r};
        console.log('r1', r, 'result: ',math.eval('r^3+A/(-2pi) r+V/pi', scope));
        //r1 1.9999528096882697 - 2.220446049250313e-16i result: 4.440892098500626e-15 - 1.1101077869995534e-15i
        //round to 5 decimals:
        console.log('rounded r1:', math.round(r,5), 'rounded result: ',math.round(math.eval('r^3+A/(-2pi) r+V/pi', scope),5));
        //rounded r1:1.99995 rounded result: 0


        //test r2
        r = r2(A, V);

        scope = {A: A, V: V, r: r};
        console.log('r2', r,'result: ', math.eval('r^3+A/(-2pi) r+V/pi', scope));
        //r2 -2.9999999737884457 - 1.6653345369377348e-16i result: 2.6645352591003757e-15 - 8.753912513083332e-15i
        //round to 5 decimals:
        console.log('rounded r2:', math.round(r,5),'rounded result: ', math.round(math.eval('r^3+A/(-2pi) r+V/pi', scope),5));
        //rounded r2: -3 rounded result: 0

        //test r3
        r = r3(A, V);

        scope = {A: A, V: V, r: r};
        console.log('r3', r, 'result: ',math.eval('r^3+A/(-2pi) r+V/pi', scope));
        //r3 1.000047164100176 + 4.440892098500626e-16i result: -1.7762101637478832e-15i
        //round to 5 decimals
        console.log('rounded r3:', math.round(r,5), 'rounded result: ',math.round(math.eval('r^3+A/(-2pi) r+V/pi', scope),5));
        //rounded r3: 1.00005 rounded result: 0

这与wolfram alpha 提供的根源一致。 {-3,1.00005,1.99995}

还要注意math.js 对象中console.log() 的大部分结果都会记录整个对象,如下所示:

r1 Complex { re=1.9999528096882697, im=-2.220446049250313e-16, toPolar=function(), more...} 

为了便于阅读,我将toString() 应用于我包含的结果。

【讨论】:

  • @chiliNUT 令人难以置信的答案。这不仅有助于解决这个特定问题,还可以为 NaN 和复数(和 mathjs)的新手提供一个良好的开端!完美的拍摄。谢谢^10
  • 顺便说一句,很高兴您已经看到了常用术语,并对其进行了标记和简化。并指出spaces implicitly mean to multiply terms 是必不可少的。
  • 无法为这个惊人的答案投票。干得好!
  • 谢谢!这可能是我最喜欢的答案。
【解决方案2】:

Edit2:对不起,我误读了原始问题,您无法在 JS 中获得负数的平方根。乘以 -1 然后乘以 'i'(-1 的平方根)是在数学 iirc 中完成的方式,但在 JS 中也不可用。

编辑:Pi 是 JavaScript 中的 Math.PI,请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math 了解所有可能的函数和属性,包括各种常量。

获得 NaN 后,您将无法继续计算,但您可以找到获得 NaN 的位置并进行修复。

你会想要这些:

parseInt(variablename, 10);

将“变量名”的值转换为整数。第二个参数是基数,在这里我假设您使用的是小数,所以我将其设置为 10。如果你没有这个,它可能会尝试根据它得到什么来转换它,所以像 parseInt('08') 这样的东西与 8 不同! 更多:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt

字符串 '10px' 将被 parseInt 更改为 10,但 'foo20' 将返回 NaN。

parseFloat(variableName);

将 'variablename' 的值转换为浮点数。

【讨论】:

  • OP 说他得到 NaN 是因为他试图取负数的平方根,而不是在将字符串解析为整数时。你说的一切都是真的(基数是 js 中的一个陷阱,值得一提),但我看不出与这个问题的相关性。
【解决方案3】:

使用 isNaN() 测试该值是否为 NaN 且没有错误

【讨论】:

    猜你喜欢
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    相关资源
    最近更新 更多