如何使用 math.round() 纠正不准确的 Javascript 数学?

发布于 2024-11-06 13:08:09 字数 5110 浏览 0 评论 0原文

几天前我发布了这段代码,但讨论似乎对 Javascript 的弱点进行了哲学性的讨论(更不用说我自己作为“程序员”的明显弱点),然后就消失了,没有澄清解决方案。我希望有人能帮助纠正这个问题。

由于一种明显被称为“浮点数学”的现象,Javascript 在下面的计算器代码中返回算术上不准确的答案(.00000004 或正确答案下方的类似答案)。有人建议我通过“在变量上调用 math.round()”来四舍五入答案,我认为这对我的目的来说效果很好,只是我的 JS 功夫太弱了,因此在上下文中这样做的语法远远超出了我的预期。

在哪里/如何拨打此电话?到目前为止,我所有的尝试都失败了,即使我确信每一次尝试都不会失败。我肯定会很感激考虑到我对该主题的低水平知识的答案。对于外面的人来说,这一定是一个扣篮。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>

<script language="javascript">

<!-- Begin Trip Tickets Savings Calc script
function  doMath4() {
    var one = parseInt(document.theForm4.elements[0].value);
    var two = parseInt(document.theForm4.elements[1].value);
    var selection = document.getElementsByName("zonett")[0].value;

    if(selection == "z4"){
        var prodZ4tt = (((one  *   two) * 4.25) *12) - (((one  *   two) * 3.75) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ4tt  +  ".");
    }
    else if(selection == "z3"){
        var prodZ3tt = (((one  *   two) * 3.75) *12) - (((one  *   two) * 3.35) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ3tt  +  ".");
    }
    else if(selection == "z2"){
        var prodZ2tt = (((one  *   two) * 3) *12) - (((one  *   two) * 2.8) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ2tt  +  ".");
    }
    else if(selection == "z1"){
        var prodZ1tt = (((one  *   two) * 2.5) *12) - (((one  *   two) * 2.3) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ1tt  +  ".");
    }
    else if(selection == "Base"){
        var prodBasett = (((one  *   two) * 1.5) *12) - (((one  *   two) * 1.5) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodBasett  +  ".");
    }
}

// End Trip Tickets Savings Calc script -->

</script>
</head>

<body>


<form name="theForm4" class="calcform">
<h2>You Do the Math: Commuter Express Trip Tickets Vs. Cash</h2>
<div class="calcform-content">
    <div class="formrow-calc">
      <div class="calcform-col1">
        <p>Days you commute on Commuter Express monthly:</p>
      </div>
      <div class="calcform-col2">
        <input type="text">
      </div>
      <div class="calcform-col3">&nbsp;</div>
    </div>
    <div class="clear"></div>


    <div class="formrow-calc">
      <div class="calcform-col1">
        <p>Daily boardings on Commuter Express Bus:</p>

        <table border="0" cellspacing="0" cellpadding="0" class="fareexampletable">
            <tr>
              <td colspan="2" class="savingsleft"><p class="ifyouride">EXAMPLE:</p></td>
              </tr>
            <tr>
              <td class="savingsleft"><p><strong>Go to work:</strong></p></td>
              <td class="savingsright"><p>1 time</p></td>
            </tr>
            <tr>
              <td class="savingsleft"><p><strong>Come home from work:</strong></p></td>
              <td class="additionline savingsright"><p>+1 time</p></td>
            </tr>
            <tr>
              <td class="savingsleft"><p><strong>Total:</strong></p></td>
              <td class="savingsright"><p>2 times</p></td>
            </tr>
          </table>
      </div>
      <div class="calcform-col2">
        <input type="text">
      </div>
      <div class="calcform-col3">&nbsp;</div>
    </div>
    <div class="clear"></div>


    <div class="formrow-calc savings-zone">
      <div class="calcform-col1">
        <p>Choose Zone:</p>
      </div>
      <div class="calcform-col2">
        <select name="zonett">
          <option value="Base">Base</option>
          <option value="z1">Zone 1</option>
          <option value="z2">Zone 2</option>
          <option value="z3">Zone 3</option>
          <option value="z4">Zone 4</option>
        </select>
      </div>
    </div>



    <div class="formrow-calc">


          <div class="calcform-col4-ce">


 <button type="submit" onclick="doMath4()" class="btn-submit"><div class="btn-submit"><img src="img/btn_savings.png" alt="Show My Yearly Savings" /></div></button> 


    </div>
    </div>
    <div class="clear">


</div>



</div>
</form>

</body>
</html>

I posted this code a couple days back, but the discussion seemed to wax philosophical about the weaknesses of Javascript (not to mention my own obvious weaknesses as a "programmer") and then died out without ever clarifying a solution. I'm hoping someone will help rectify that.

Due to a phenomenon apparently known as "floating point math," Javascript returns an arithmetically inaccurate answer (.00000004 or similar below the correct answer) in the calculator code below. I was advised to round the answer up by "calling math.round() on the variable," which I think would work fine for my purposes, only my JS kung fu was too weak, and the syntax of doing so in context has thus far eluded me.

Where/how to I make this call? So far all my attempts have failed, even when I thought for sure each would not. I would sure appreciate an answer that takes into account my low-level knowledge of the subject. This has got to be a slam-dunk for somebody out there.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>

<script language="javascript">

<!-- Begin Trip Tickets Savings Calc script
function  doMath4() {
    var one = parseInt(document.theForm4.elements[0].value);
    var two = parseInt(document.theForm4.elements[1].value);
    var selection = document.getElementsByName("zonett")[0].value;

    if(selection == "z4"){
        var prodZ4tt = (((one  *   two) * 4.25) *12) - (((one  *   two) * 3.75) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ4tt  +  ".");
    }
    else if(selection == "z3"){
        var prodZ3tt = (((one  *   two) * 3.75) *12) - (((one  *   two) * 3.35) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ3tt  +  ".");
    }
    else if(selection == "z2"){
        var prodZ2tt = (((one  *   two) * 3) *12) - (((one  *   two) * 2.8) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ2tt  +  ".");
    }
    else if(selection == "z1"){
        var prodZ1tt = (((one  *   two) * 2.5) *12) - (((one  *   two) * 2.3) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodZ1tt  +  ".");
    }
    else if(selection == "Base"){
        var prodBasett = (((one  *   two) * 1.5) *12) - (((one  *   two) * 1.5) *12);
        alert("Your yearly savings if you buy Trip Tickets is $"  +  prodBasett  +  ".");
    }
}

// End Trip Tickets Savings Calc script -->

</script>
</head>

<body>


<form name="theForm4" class="calcform">
<h2>You Do the Math: Commuter Express Trip Tickets Vs. Cash</h2>
<div class="calcform-content">
    <div class="formrow-calc">
      <div class="calcform-col1">
        <p>Days you commute on Commuter Express monthly:</p>
      </div>
      <div class="calcform-col2">
        <input type="text">
      </div>
      <div class="calcform-col3"> </div>
    </div>
    <div class="clear"></div>


    <div class="formrow-calc">
      <div class="calcform-col1">
        <p>Daily boardings on Commuter Express Bus:</p>

        <table border="0" cellspacing="0" cellpadding="0" class="fareexampletable">
            <tr>
              <td colspan="2" class="savingsleft"><p class="ifyouride">EXAMPLE:</p></td>
              </tr>
            <tr>
              <td class="savingsleft"><p><strong>Go to work:</strong></p></td>
              <td class="savingsright"><p>1 time</p></td>
            </tr>
            <tr>
              <td class="savingsleft"><p><strong>Come home from work:</strong></p></td>
              <td class="additionline savingsright"><p>+1 time</p></td>
            </tr>
            <tr>
              <td class="savingsleft"><p><strong>Total:</strong></p></td>
              <td class="savingsright"><p>2 times</p></td>
            </tr>
          </table>
      </div>
      <div class="calcform-col2">
        <input type="text">
      </div>
      <div class="calcform-col3"> </div>
    </div>
    <div class="clear"></div>


    <div class="formrow-calc savings-zone">
      <div class="calcform-col1">
        <p>Choose Zone:</p>
      </div>
      <div class="calcform-col2">
        <select name="zonett">
          <option value="Base">Base</option>
          <option value="z1">Zone 1</option>
          <option value="z2">Zone 2</option>
          <option value="z3">Zone 3</option>
          <option value="z4">Zone 4</option>
        </select>
      </div>
    </div>



    <div class="formrow-calc">


          <div class="calcform-col4-ce">


 <button type="submit" onclick="doMath4()" class="btn-submit"><div class="btn-submit"><img src="img/btn_savings.png" alt="Show My Yearly Savings" /></div></button> 


    </div>
    </div>
    <div class="clear">


</div>



</div>
</form>

</body>
</html>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

失去的东西太少 2024-11-13 13:08:09

一般来说,您希望最后舍入,因此您可以保持数学准确性,直到显示数据为止。

以下是我将如何实现您的小库:

var SavingsLib = {
    round : function(val, digits) {
        var pow = Math.pow(10, digits);
        return Math.round(pow * val) / pow;
    },

    padCurrency : function (val) {
        var str = val.toString();
        var parts = str.split(".");
        return parts.length > 1 && parts[1].length == 1 ? str + "0" : str;
    },

    processForm : function() {
        var daysPerMonth = parseInt(document.theForm4.elements[0].value);
        var boardingsPerDay = parseInt(document.theForm4.elements[1].value);
        var zone = document.getElementsByName("zonett")[0].value;

        var savings = 0;
        if(zone == "z4") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 4.25, 3.75);
        else if(zone == "z3") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 3.75, 3.35);
        else if(zone == "z2") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 3, 2.8);
        else if(zone == "z1") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 2.5, 2.3);
        else if(zone == "Base") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 1.5, 1.5);

        this.showMessage(savings);

        return false; // Don't submit form
    },

    calculateSavings : function(daysPerMonth, boardingsPerDay, price1, price2) {
        var amount1 = (((daysPerMonth * boardingsPerDay) * price1) * 12);
        var amount2 = (((daysPerMonth * boardingsPerDay) * price2) * 12);

        return this.round(amount1 - amount2, 2);
    },

    showMessage : function(savings) {
        alert("Your yearly savings if you buy Trip Tickets is $" + this.padCurrency(savings));
    }
}

我的更改:

  • 将函数封装到命名空间对象中
  • 将数学提取到单个方法中,以便您可以进行一次调用
  • 提取将消息显示到方法中,以便您可以轻松修改它
  • 添加了舍入到数字的函数(因此1.4500001变为1.45而不是1)
  • 添加了垫币功能(因此1.4变为1.40

In general you want to round last, so you maintain mathematical accuracy up until the point that data is displayed.

Here is how I would implement your little library:

var SavingsLib = {
    round : function(val, digits) {
        var pow = Math.pow(10, digits);
        return Math.round(pow * val) / pow;
    },

    padCurrency : function (val) {
        var str = val.toString();
        var parts = str.split(".");
        return parts.length > 1 && parts[1].length == 1 ? str + "0" : str;
    },

    processForm : function() {
        var daysPerMonth = parseInt(document.theForm4.elements[0].value);
        var boardingsPerDay = parseInt(document.theForm4.elements[1].value);
        var zone = document.getElementsByName("zonett")[0].value;

        var savings = 0;
        if(zone == "z4") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 4.25, 3.75);
        else if(zone == "z3") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 3.75, 3.35);
        else if(zone == "z2") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 3, 2.8);
        else if(zone == "z1") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 2.5, 2.3);
        else if(zone == "Base") savings = this.calculateSavings(daysPerMonth, boardingsPerDay, 1.5, 1.5);

        this.showMessage(savings);

        return false; // Don't submit form
    },

    calculateSavings : function(daysPerMonth, boardingsPerDay, price1, price2) {
        var amount1 = (((daysPerMonth * boardingsPerDay) * price1) * 12);
        var amount2 = (((daysPerMonth * boardingsPerDay) * price2) * 12);

        return this.round(amount1 - amount2, 2);
    },

    showMessage : function(savings) {
        alert("Your yearly savings if you buy Trip Tickets is $" + this.padCurrency(savings));
    }
}

My changes:

  • Encapsulated functions into an object for namespacing
  • Extracted the math out into a single method so you can make one round call
  • Extracted the showing of the message into a method so you can modify it easily
  • Added a round-to-digits function (So 1.4500001 becomes 1.45 instead of 1)
  • Added a pad currency function (So 1.4 becomes 1.40)
老娘不死你永远是小三 2024-11-13 13:08:09

您可以使用 Math.round 编写一个拼凑,但这会造成损失(不确定这是否适用于您的示例,看起来似乎可以)。您可能想要的是修复:

alert((102.000000004).toFixed(2)); // alerts "102.00"

这在 IE 中不会四舍五入,但据我所知,这对您的情况并不重要。

(文档:https://developer.mozilla.org/en/JavaScript/ Reference/Global_Objects/Number/toFixed , http://www.codingforums.com /showthread.php?t=102421http://msdn. microsoft.com/en-us/library/sstyff0z.aspx

编辑:打算将其放在评论中,但 Markdown 在那里不起作用?仍然习惯这样......

无论如何,如果您愿意,您也可以使用 Math.round 的拼凑:

alert(Math.round(val * 100) / 100);

这可能仍然显示愚蠢的浮动问题,为此您可以使用另一个 .toFixed (现在您 100% 确定)没有剩余的小数位,您没有正确舍入):

alert((Math.round(val * 100) / 100).toFixed(2));

编辑:集成:

将其添加到脚本块的顶部:

function roundNicely(val) {
     return (Math.round(val * 100) / 100).toFixed(2);
}

然后在警报中,将值 prodBasett 包装在函数调用中:< code>roundNicely(prodBasett) (其他警报也类似)

这有意义吗?

You can write a kludge with Math.round, but that will nuke cents (not sure if this applies in your example, it sort of looks like it could). What you may want is toFixed:

alert((102.000000004).toFixed(2)); // alerts "102.00"

This does NOT round in IE, but from what I can tell this will not matter in your case.

(docs: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Number/toFixed , http://www.codingforums.com/showthread.php?t=102421 , http://msdn.microsoft.com/en-us/library/sstyff0z.aspx )

Edit: intended to put this in the comments, but markdown doesn't work there? Still getting used to SO...

Anyhow, you can also use a kludge with Math.round if you prefer:

alert(Math.round(val * 100) / 100);

Which may still display the silly float issues, for which you could use another .toFixed (and now you're 100% sure there's no leftover decimal places you're not rounding properly):

alert((Math.round(val * 100) / 100).toFixed(2));

Edit: to integrate:

Add this at the top of your script block:

function roundNicely(val) {
     return (Math.round(val * 100) / 100).toFixed(2);
}

Then in your alerts, wrap the value prodBasett in the function call: roundNicely(prodBasett) (and similar for the other alerts)

Does that make sense?

哭了丶谁疼 2024-11-13 13:08:09

非常简单

var prodZ4tt = Math.round(((one  *   two) * 4.25) *12) - (((one  *   two) * 3.75) *12);

尽管您可能对语法感到困惑是可以理解的,因为 JavaScript 不是以其直观的做事方式而闻名。 ;)

注意: 这会将数字四舍五入到最接近的整数,而不是“向上舍入”。

It's very simple:

var prodZ4tt = Math.round(((one  *   two) * 4.25) *12) - (((one  *   two) * 3.75) *12);

Although it's understandable why you might get confused about syntax, since JavaScript is not known for its intuitive way of doing things. ;)

Note: This rounds the number to the nearest integer, it doesn't "round up."

久隐师 2024-11-13 13:08:09

对于需要精度的情况,您必须需要一个数学“任意精度库”......您可以在这里找到一篇好文章。

http://blog.thatscaptaintoyou.com/introducing- big-js-任意-精度-math-for-javascript/

JavaScript 本身具有 round、ceil 和 Floor 来将浮点数转换为整数。

var fl = 349.12783691847;
Math.round(fl) // 349
Math.ceil(f1) // 350
Math.floor(fl) // 349

当您进行数学运算时,使用分配律和正确使用括号是很好的做法。

Math.round(((((a + b) * (c - d)) % e) * f));

请小心“NaN”(http://en.wikipedia.org/wiki/NaN) 和非数字类型。

祝你今天过得愉快

For that cases when you need precision, you must need an Math "Arbitrary Precision Library"... you could find a good article here.

http://blog.thatscaptaintoyou.com/introducing-big-js-arbitrary-precision-math-for-javascript/

Javascript natively have round, ceil and floor to convert floats to integers.

var fl = 349.12783691847;
Math.round(fl) // 349
Math.ceil(f1) // 350
Math.floor(fl) // 349

when you do math operations, is good practice use distributivity, and properly use of parenthesis.

Math.round(((((a + b) * (c - d)) % e) * f));

Be careful with "NaN" (http://en.wikipedia.org/wiki/NaN) and non Number types.

have a nice day

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文