Compare decimal strings in Javascript

goodvibration :

I have an input of two strings, each of which representing a non-negative rational number in decimal format.

Given these two strings x and y, I would like to check if the numeric value represented by x is larger than the numeric value represented by y.

These two values can be very large, as well as to extend to a very high precision (i.e., many digits after the decimal-point).

As such, I cannot rely on Number(x) > Number(y) to do the job.

Instead, I have implemented the following function:

function isLarger(x, y) {
    const xParts = x.split(".").concat("");
    const yParts = y.split(".").concat("");
    xParts[0] = xParts[0].padStart(yParts[0].length, "0");
    yParts[0] = yParts[0].padStart(xParts[0].length, "0");
    xParts[1] = xParts[1].padEnd  (yParts[1].length, "0");
    yParts[1] = yParts[1].padEnd  (xParts[1].length, "0");
    return xParts.join("").localeCompare(yParts.join("")) == 1;
}

I have conducted extensive testing, by generating random input x and y, and comparing the result of isLarger(x, y) to the value of the expression Number(x) > Number(y).

Of course, for the reasons mentioned above, I cannot rely on the value of the expression Number(x) > Number(y) to be correct for every possible input x and y.

So I would like some kind of feedback on the function above:

  • Does it have any caveats in it?
  • Is there perhaps a simpler way of achieving this?
Petr Srníček :

I don't see any caveats in your solution, but the last line is unnecessarily complex. Instead of

return xParts.join("").localeCompare(yParts.join("")) == 1;

You could simply use this:

return xParts.join("") > yParts.join("");

Simpler solution with some limitations on input values

If you can be absolutely sure that your input will never contain numbers with unecessary leading zeros (eg. 001 instead of 1) or decimal numbers starting with a point (eg. .1 instead of 0.1) you can signficantly simplify the comparison by first comparing the number of digits in the integer parts.

More digits in the integer part means a greater number, less digits means a smaller number.

When the number of integer digits is the same, a simple string comparison is basically sufficient. Only one padding operation is necessary - y needs to be padded with trailing zeros in order not to get truthy result if x equals y but contains more trailing zeros (because '211.00' > '211.0' is true).

function isLarger(x, y) {
    const xIntLength = x.search(/\.|$/); /* Finds position of . or end of string */
    const yIntLength = y.search(/\.|$/); /* Finds position of . or end of string */
    /* Compare lengths of int part */
    if (xIntLength !== yIntLength) {
      return xIntLength > yIntLength;
    } else {
    /* Add decimal point to Y if not present and add  trailing zeros
       because otherwise eg. '2.00' > '2.0' would return true */
      const yWithDecimalPoint = y.includes('.') ? y : y + '.';
      const paddedY = yWithDecimalPoint.padEnd(x.length,'0');
      return x > paddedY;
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=12030&siteId=1