class-validator icon indicating copy to clipboard operation
class-validator copied to clipboard

IsNumber decorator fails on values ABS(x) < 0.000001

Open igor-tatarnikov opened this issue 2 years ago • 2 comments

Hi team,

IsNumber decorator throws error, when a small value is analyzed (ABS(x) < 0.000001. It happens because such a small value has exponential format -->

> parseFloat('0.000001')
< 0.000001
> parseFloat('0.0000001')
< 1e-7

The following code fails, because value.toString().split('.')[1] is not available - there's no . in the string!

  if (options.maxDecimalPlaces !== undefined) {
    let decimalPlaces = 0;
    if (value % 1 !== 0) {
      decimalPlaces = value.toString().split('.')[1].length;
    }
    if (decimalPlaces > options.maxDecimalPlaces) {
      return false;
    }
  }

https://github.com/typestack/class-validator/blob/2ef8ff0f32be53e75dade2a0b86b158d87427176/src/decorator/typechecker/IsNumber.ts#L34

igor-tatarnikov avatar Jul 25 '22 08:07 igor-tatarnikov

A fix proposal (I wasn't allowed to create a pull request for some reason, sorry)

  if (options.maxDecimalPlaces !== undefined) {
    let decimalPlaces = 0;
    if (value % 1 !== 0) {
      const stringValue = value.toString();

      if (stringValue.indexOf('.') > -1){
        decimalPlaces = stringValue.split('.')[1]?.length ?? 0;
      }
      else if (stringValue.indexOf('e-') > -1) {
        decimalPlaces = parseInt(stringValue.split('e-')[1] ?? '0');
      }
    }
    if (decimalPlaces > options.maxDecimalPlaces) {
      return false;
    }
  }

igor-tatarnikov avatar Jul 25 '22 08:07 igor-tatarnikov

All the indexOf and split stuff seems very arcane for number manipulation. Is there no better, numeric way to get the decimal places?

Clashsoft avatar Jul 29 '22 12:07 Clashsoft

@Clashsoft I'm afraid, there is no reliable, numeric way to determine how many digits are present in the fractional part. Theoretically, we should be able to simply multiply the value by 10 until we get an integer, but as we all know, float operations may end up with an unexpected result and it won't work in some cases.

V3RON avatar Nov 16 '22 08:11 V3RON