在JavaScript中添加和比较两个十进制数

时间:2019-05-17 00:23:01

标签: javascript

我正在尝试添加两个十进制数字(参数可以是数字或被解析前为数字的字符串),然后将结果与resultInput进行比较。问题是系统无法足够准确地表示浮点数。例如,0.1 + 0.2 = 0.30000000000000004。因此,我尝试使用toFixed()方法使用定点表示法格式化数字。运行代码时,我得到false。不知道我在哪里弄错了。让我知道您是否有任何想法。

    function calc(firstNumber, secondNumber, operation, resultInput) {
      let a = parseFloat(firstNumber); //Number()
      let b = parseFloat(secondNumber); //Number()
      let c;
      let d = parseFloat(resultInput);
      console.log(JSON.stringify(`value of d : ${d}`)); //"value of d : NaN"
    
      switch (operation) {
        case '+':
          c = a + b;
          break;
        case '-':
          c = a - b;
          break;
        case '*':
          c = a * b;
          break;
        case '/':
         if (b === 0 && 1 / b === -Infinity) {
           r = Infinity;
         } else {
           r = a / b;
         }
          break;
        default:
          console.log(`Sorry, wrong operator: ${operation}.`);
      }
      console.log(JSON.stringify(`value of c: ${c}`)); // "value of c: 0.30000000000000004"
      let f = +c.toFixed(1);
      let e = +d.toFixed(1);
    
      console.log(JSON.stringify(`value of f: ${f}`)); // "value of f: 0.3"
      console.log(typeof f); //number
      console.log(JSON.stringify(`value of d: ${d}`)); // "value of d: NaN"
      console.log(typeof d); //number
      console.log(JSON.stringify(`value of e: ${e}`)); // "value of e: NaN"
      console.log(typeof e); //number
    
      if (f !== e) return false;
      // if (!Object.is(f, e)) return false;
      return true;
    }
    
    console.log(calc('0.1', '0.2', '+', '0.3'));

3 个答案:

答案 0 :(得分:2)

可以创建一个测试两个数字是否足够接近以被称为相等的函数,而不是在字符串之间来回转换。您确定一些小增量,如果数字至少接近该数字,则称其为好。

function almost(a, b, delta = 0.000001){
    return Math.abs(a - b) < delta
}

// not really equal
console.log("equal?", 0.2 + 0.1 === 0.3)

// but good enough
console.log("close enough?", almost(0.2 + 0.1, 0.3))

答案 1 :(得分:2)

我多次运行您的代码,并且没有问题。我刚刚发现您发布的'0.3'具有一个特殊字符,看起来像3,但不是3。因此,当您想在JS上运行它时,将显示一个错误。因此,您的解决方案是正确的。在这里检查。

function calc(firstNumber, secondNumber, operation, resultInput) {
  let a = parseFloat(firstNumber);
  let b = parseFloat(secondNumber);
  let aux = parseFloat(resultInput);
  let r;

  switch (operation) {
    case '+':
      r = a + b;
      break;
    case '-':
      r = a - b;
      break;
    case '*':
      r = a * b;
      break;
    case '/':
      if (b !== 0) {
        r = a / b;
      } else {
        r = 0;
      }
      break;
    default:
      console.log(`Sorry, wrong operator: ${operation}.`);
  }

  return (+r.toFixed(1)) === (+aux.toFixed(1));
}

console.log(calc('0.1', '0.2', '+', '0.3'));

答案 2 :(得分:0)

这不是直接答案,而是有关toFixed()和浮点数行为的解释:

toFixed()返回一个文本。原因之一是,通常不存在数字,可以表示toFixed()的结果。因此,仅将此功能用于显示,而不能像此处那样用于计算。

let f = +c.toFixed(1);
let e = +d.toFixed(1);

toPrecision(18)可以显示数字的所有相关数字。一些例子:

 (0.1).toPrecision(18) // => 0.100000000000000006
 (0.2).toPrecision(18) // => 0.200000000000000011
 (0.3).toPrecision(18) // => 0.299999999999999989

这些示例说明了为什么0.1+0.20.3不同。

toFixed(1)相同的示例:

(+(0.1).toFixed(1)).toPrecision(18) // => 0.100000000000000006
(+(0.2).toFixed(1)).toPrecision(18) // => 0.200000000000000011
(+(0.3).toFixed(1)).toPrecision(18) // => 0.299999999999999989

它什么都没有改变:toFixed(1)格式化数字,而+符号将其转换回最近的现有数字。

这不是JavaScript问题,而是使用IEEE 754(基于二进制数)的基于计算机的浮点数的问题。大多数硬件都支持这种浮动。

在计算机数学中,通常使用绝对或相对增量值来比较浮点数的相等性。绝对增量示例:

function isEqual( num1, num2, epsilon )
{
    return Math.abs( num1 - num2 ) <= epsilon;
}

isEqual( 0.1 + 0.2, 0.3, 1e-10 ) // => true

数据库支持DECIMAL(5.1)之类的数据类型。这里是0.1+0.2 == 0.3,因为内部使用整数并仅格式化输出。

具有2个小数位(欧元,美分)的货币的JavaScript示例:

// scan user input:
cent = round( euro * 100 );

// adding cents:
cent3 = cent1 + cent2;

// print cents as euro
(cent/100).toFixed(2)+"€"