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?
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;
}
}