From d315908ecc80b32e156c21e8fe32df89904a7b4a Mon Sep 17 00:00:00 2001 From: dhmemi Date: Tue, 14 Nov 2023 07:05:28 +0000 Subject: [PATCH] fix multiple of float number --- src/json-validator.cpp | 11 ++++++++--- test/issue-293.cpp | 37 +++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/json-validator.cpp b/src/json-validator.cpp index 438ced0..1fd0de1 100644 --- a/src/json-validator.cpp +++ b/src/json-validator.cpp @@ -863,9 +863,14 @@ class numeric : public schema // multipleOf - if the remainder of the division is 0 -> OK bool violates_multiple_of(T x) const { - auto multiple = x / multipleOf_.second; - auto error = std::abs((multiple - std::round(multiple)) * multipleOf_.second); - return error > std::numeric_limits::epsilon(); + double res = std::remainder(x, multipleOf_.second); + double multiple = std::fabs(x / multipleOf_.second); + if (multiple > 1) { + res = res / multiple; + } + double eps = std::nextafter(x, 0) - static_cast(x); + + return std::fabs(res) > std::fabs(eps); } void validate(const json::json_pointer &ptr, const json &instance, json_patch &, error_handler &e) const override diff --git a/test/issue-293.cpp b/test/issue-293.cpp index fb566e1..dbfdac9 100644 --- a/test/issue-293.cpp +++ b/test/issue-293.cpp @@ -1,27 +1,32 @@ #include "nlohmann/json-schema.hpp" +using nlohmann::json_schema::json_validator; + +template +int should_throw(const nlohmann::json &schema, T value) +{ + try { + json_validator(schema).validate(value); + } catch (const std::exception &ex) { + return 0; + } + return 1; +} + int main(void) { - using nlohmann::json_schema::json_validator; json_validator({{"type", "number"}, {"multipleOf", 0.001}}).validate(0.3 - 0.2); - json_validator({{"type", "number"}, {"multipleOf", 3.3}}).validate(8.0 - 1.4); - json_validator({{"type", "number"}, {"multipleOf", 1000.01}}).validate((1000.03 - 0.02) * 15.0); + json_validator({{"type", "number"}, {"multipleOf", 0.001}}).validate(0.030999999999999993); + json_validator({{"type", "number"}, {"multipleOf", 0.100000}}).validate(1.9); + json_validator({{"type", "number"}, {"multipleOf", 100000.1}}).validate(9000009); - int expect_exception = 2; - try { - json_validator({{"type", "number"}, {"multipleOf", 0.001}}).validate(0.3 - 0.2005); - } catch (const std::exception &ex) { - expect_exception--; - } + int exc_count = 0; + exc_count += should_throw({{"type", "number"}, {"multipleOf", 0.001}}, 0.3 - 0.2005); + exc_count += should_throw({{"type", "number"}, {"multipleOf", 1000.02}}, (1000.03 - 0.02) * 15.0); + exc_count += should_throw({{"type", "number"}, {"multipleOf", 100000.11}}, 9000009); - try { - json_validator({{"type", "number"}, {"multipleOf", 1000.02}}).validate((1000.03 - 0.02) * 15.0); - } catch (const std::exception &ex) { - expect_exception--; - } - - return expect_exception; + return exc_count; }