Skip to content
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

Add/comment/multipleof #1219

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1744,6 +1744,10 @@ <h4 id="name-multipleof">
<p id="section-6.2.1-2">
A numeric instance is valid only if division by this keyword's value results in
an integer.<a href="#section-6.2.1-2" class="pilcrow">¶</a></p>
<p id="section-6.2.1-2">
To ensure consistent validation:
- Use scaled integers (e.g., represent $4.02 as 402 with 'multipleOf: 1')
- If floating-point values are necessary, use binary-friendly numbers (e.g., 0.5, 0.25, 0.125)</p><a href="#section-6.2.1-2" class="pilcrow">¶</a></p>
Comment on lines +1748 to +1750
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really the recommendation we want to make?

Copy link

@mwadams mwadams Dec 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say "no".

Use of scaled integers is ok but is a choice not a recommendation. And we don't have direct support for a scaled integer - e.g. defining the scale. You push a whole new problem onto consumers.

When it comes to non-integers it isn't really meaningful; why would we be recommending that people only use "particular values". And then there is the problem of representation on all platforms (e.g. 1.3, 2.4, 5.6 cannot be represented precisely as a 32 bit float).

Copy link
Member

@gregsdennis gregsdennis Dec 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A use case could be defining currency, for example dollars & cents. You'd want to ensure that your data only has a penny ($0.01) resolution.

But the point is that we don't want to force users into a scenario where they should be trying to figure out the nuances of binary float arithmetic while writing their schemas.

I think that the very most, we should be leaving a note that some implementations may use IEEE754 math.

I do think the way that the spec is worded is pretty clever, though.

6.2.1. multipleOf

The value of "multipleOf" MUST be a number, strictly greater than 0.
A numeric instance is valid only if division by this keyword's value results in an integer.

In C#,

double a = .0075;  // IEEE754
double b = .0001;
decimal c = .0075m;
decimal d = .0001m;

Console.WriteLine("double");
Console.WriteLine(a / b);
Console.WriteLine(a % b);
Console.WriteLine();
Console.WriteLine("decimal");
Console.WriteLine(c / d);
Console.WriteLine(c % d);

outputs

double
75
9.999999999999937E-05

decimal
75
0.0000

So following the method prescribed by the spec (using division instead of modulation) actually produces the correct result, even with IEEE754 math.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing monetary values as cents is a good idea, to keep all math as integers, but a better way of specifying that in the schema is with type: integer not multipleOf: 1.

I don't think we want to add anything like scale into the spec, though -- this should be defined and controlled by the individual application.

We may want to add a note that tooling might implement the multipleOf keyword using modulo calculations, as a lead-in to the warning about imprecision with floating point storage.

</section>
<section id="section-6.2.2">
<h4 id="name-maximum">
Expand Down
Loading