admin管理员组

文章数量:1394593

I am trying to add two decimal numbers (arguments could be numbers or strings that are numbers before they are parsed) and pare the oute with the resultInput. The problem is that the floating-point numbers cannot be represented accurately enough by the system. For example, 0.1 + 0.2 = 0.30000000000000004. So, I am trying to use toFixed() method to format a number using fixed-point notation. I am getting false when I run the code. Not sure where I am getting it wrong. Let me know if you have any ideas.

    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'));

I am trying to add two decimal numbers (arguments could be numbers or strings that are numbers before they are parsed) and pare the oute with the resultInput. The problem is that the floating-point numbers cannot be represented accurately enough by the system. For example, 0.1 + 0.2 = 0.30000000000000004. So, I am trying to use toFixed() method to format a number using fixed-point notation. I am getting false when I run the code. Not sure where I am getting it wrong. Let me know if you have any ideas.

    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'));

Share Improve this question edited May 17, 2019 at 4:18 John John asked May 17, 2019 at 0:23 John JohnJohn John 1,5004 gold badges22 silver badges45 bronze badges 9
  • .toFixed() returns a string so you'll need to convert it back to a number. let f = parseFloat(c.toFixed(1)); – zer00ne Commented May 17, 2019 at 0:25
  • this is what I want. To pare two strings "0.3" === "0.3" //true. or I am missing something? – John John Commented May 17, 2019 at 0:28
  • Don't wrap numbers with quotes they bee strings. Strings do not behave like numbers. – zer00ne Commented May 17, 2019 at 0:28
  • I need them to be strings as inputs. This is the condition of the task I am trying to solve. – John John Commented May 17, 2019 at 0:30
  • 1 You appear to have some invisible characters showing up in your result string. You may want to consider parsing and .toFixeding result as well to ensure accuracy – Hamms Commented May 17, 2019 at 0:39
 |  Show 4 more ments

3 Answers 3

Reset to default 4

Rather than converting back and forth to/from strings, you can create a function that tests if two numbers are close enough to be called equal. You decide some small delta and if the numbers are at least that close, you call it good.

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))

I run your code several times and there is no problem with it. I just found that the '0.3' that you posted, it has an special character that looks like 3 but its not 3. So, when you want to run it on JS it will show an error. So your solution was correct. Check here.

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'));

This is not an direct answer, but an explanation about toFixed() and behavior of floating point numbers:

toFixed() returns a text. One reason is, that generally no number exists, the can represent the result of toFixed(). So use this function only for displaying, but not for calculating like here.

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

toPrecision(18) is good to display all relevant digits of a number. Some examples:

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

The examples explains, why 0.1+0.2 is not the same as 0.3.

Same examples with 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

It changed nothing: toFixed(1) formats the number, and the + sign convert it back to the nearest existing number.

This is not a JavaScript issue, it is an issue of puter based floating points number using IEEE 754 (binary based numbers). Most hardware support this kind of floats.

In puter mathematics it is usual, to pare equality of floating point numbers by using absolute or relative delta values. Example for absolute delta:

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

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

Databases support dataytpes like DECIMAL(5.1). Here 0.1+0.2 == 0.3, because the use internally interger numbers and format only the output.

JavaScript example for currency with 2 fraction digits (euro,cent):

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

// adding cents:
cent3 = cent1 + cent2;

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

本文标签: Adding and comparing two decimal numbers in JavaScriptStack Overflow