-
-
Notifications
You must be signed in to change notification settings - Fork 887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validation of multipleOf keyword with decimal numbers #652
Comments
There is an option multipleOfPrecision that does a similar thing, see options. |
Ugh...sorry about that. Somehow I overlooked it. |
@epoberezkin Definitely room for simplification. I tend to leave my code less optimized for readability when submitting to these discussions. |
So, I found a nice drop in replacement for the getDecimalPlaces function which works off of regex pattern matching and is over twice as fast according to jsperf. function getDecimalPlaces(num) {
var match = (''+num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if (!match) { return 0; }
return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
} The only thing to note with this function is that provided numbers within strings such as '1.00' will return 2. The actual validation could be simplified to this: const multiplier = Math.pow(
10,
Math.max(getDecimalPlaces(fieldValue), getDecimalPlaces(multipleOfValue))
);
return Math.round(fieldValue * multiplier) % Math.round(multipleOfValue * multiplier) === 0; |
Could be a related issue: Maybe a fix could be ported from there? |
We're also suffering from this: json-schema-faker/json-schema-faker#379 |
Any updates on when this would be resolved? |
Maybe something like that should solve. |
Hi everyone, i'm using this lib currently, is there a dev release with a fix ? |
For people who are using AJV with JavaScript or TypeScript and having the issue of validate floating point number, try to build a custom keyword. Problem import Ajv from "ajv";
const ajv = new Ajv();
const schema = {
type: "object",
properties: {
price: { type: "number", minimum: 0, multipleOf: 0.01 },
},
required: ["price"],
additionalProperties: false,
};
const data = {price: 2.22}
// will be false
ajv.validate(schema, data) Because in JS Solution import Ajv from "ajv";
import NP from "number-precision";
const ajv = new Ajv();
ajv.addKeyword({
keyword: "customMultipleOf",
type: "number",
compile(schema) {
return (data) => Number.isInteger(NP.divide(data, schema));
},
errors: false,
metaSchema: {
type: "number",
},
});
const schema = {
type: "object",
properties: {
price: { type: "number", minimum: 0, customMultipleOf: 0.01 },
},
required: ["price"],
additionalProperties: false,
};
const data = {price: 2.22} This will work at least in my case. |
You can actually replace the standard implementation too using removeKeyword first. |
Yes, I just ty and it works. import Ajv from "ajv";
import NP from "number-precision";
const ajv = new Ajv();
// remove default keyword: multipleOf
ajv.removeKeyword("multipleOf");
ajv.addKeyword({
keyword: "multipleOf",
type: "number",
compile(schema) {
return (data) => Number.isInteger(NP.divide(data, schema));
},
errors: false,
metaSchema: {
type: "number",
},
});
const schema = {
type: "object",
properties: {
price: { type: "number", minimum: 0, multipleOf: 0.01 },
},
required: ["price"],
additionalProperties: false,
};
const data = {price: 2.22} |
Reviewing the history it doesn't look like this will be changed plus there is a workaround. |
Due to the rounding issues (IEEE-754) with computations using decimal numbers in several languages including JavaScript, the validation of fields using the "multipleOf" or "divisibleBy" properties will often erroneously fail validation.
As an example, using a field with the "multipleOf" property set to 0.015, the validation will fail when the field is set to valid values such as 0.135, 0.165, 0.195, 0.225, etc. All of said values are divisible by 0.015.
This can be remedied by changing the algorithm used to validate the "multipleOf" and "divisibleBy" properties. The change involves scaling both the field and "multipleOf" values to integer equivalents and then performing the required validation on those values. Below is some code that I had written for another JSON validator which had the same issue.
What version of Ajv are you using? Does the issue happen if you use the latest version?
5.5.2
Are you going to resolve the issue?
Unfortunately, I do not have time to resolve the issue on my own...
The text was updated successfully, but these errors were encountered: