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

Fix signed zero bugs & refine numeric restrictions #537

Open
kpreid opened this issue Oct 3, 2024 · 6 comments
Open

Fix signed zero bugs & refine numeric restrictions #537

kpreid opened this issue Oct 3, 2024 · 6 comments
Labels
area: data Things related to the data structures underlying the world, and the functions that manipulate them. kind: bug Something isn't working as it should

Comments

@kpreid
Copy link
Owner

kpreid commented Oct 3, 2024

Problem

There's a correctness bug lurking in our use of ordered_float::NotNan: positive and negative zero, -0.0 and 0.0, compare equal, and this can cause different outcomes of further operations (notably division or reciprocal). This means that using them as cache keys is invalid except where the sign is known to make no difference.

Closely related, but not strictly a bug: there are cases where NotNan is less restrictive than we would benefit from; for example, Rgba allows an alpha less than 0 or greater than 1, but this is meaningless.

Solution

All of our uses of NotNan (we don't have any uses that aren't for cache-key/change-detection purposes, I believe) should be replaced with wrappers that are either more restrictive or consider positive and negative zero distinct, as is appropriate for the application.

If some of the resulting wrappers seem more generally applicable, it might make sense to contribute them back to ordered_float.

@kpreid kpreid added kind: bug Something isn't working as it should area: data Things related to the data structures underlying the world, and the functions that manipulate them. labels Oct 3, 2024
kpreid added a commit that referenced this issue Oct 19, 2024
This will be used to enforce stronger restrictions on color components,
which will reduce the number of edge cases color processing code must
consider, and remove the the hazard of distinct negative zero
(<#537>).
kpreid added a commit that referenced this issue Oct 19, 2024
It is now impossible for colors to contain negative components,
which will reduce the number of edge cases color processing code must
consider, and remove the the hazard of distinct negative zero
(<#537>).

(There are some uses for negative-valued RGB components to represent
colors that are outside of the gamut of the chosen color space, but
I don’t know enough about that extension to know how to handle it
correctly.)

We’re probably also going to want a type restricted from 0 to 1, for
strict alpha and reflectance calculations, but `PositiveSign` is a
straightforward improvement of the overall situation.
@kpreid
Copy link
Owner Author

kpreid commented Oct 19, 2024

Commit 20cd9d6 replaces all uses of NotNan within color types with the new numeric wrapper PositiveSign.

Next steps:

  • There's a lot of places where what is needed is a 0-1 restricted type: alpha, reflectance RGB, bloom intensity option, progress bar fill. I haven’t thought of a good name for it.
  • Replace NotNan with PositiveSign in uses like the view distance in graphics options. (That’s separately clamped to a nonzero minimum value, so it's not strictly required, but we might as well.)

@kpreid
Copy link
Owner Author

kpreid commented Oct 21, 2024

As of commit ef1a45e, there is a ZeroOne type, and it is used by Rgba for alpha and GraphicsOptions for bloom blending.

@kpreid
Copy link
Owner Author

kpreid commented Oct 29, 2024

As of commit 30ceaed, GraphicsOptions no longer uses NotNan.

@kpreid
Copy link
Owner Author

kpreid commented Oct 30, 2024

Remaining non-incidental uses of NotNan:

  • Points/vectors (can't be PositiveSign since they can be negative):
    • Spawn::eye_position
    • Spawn::look_direction
    • SpacePhysics::gravity
  • Fluff::BlockImpact::velocity (can be PositiveSign)
    (update: done in commit e6eb4a2)
  • FpsCounter::average_frame_time_seconds (can be PositiveSign)
    (update: done in commit fc3f723)
  • Conversion methods on color types

kpreid added a commit that referenced this issue Nov 1, 2024
This is part of <#537> —
`PositiveSign` gives us a guarantee of no negative zeroes, which
compare equal to positive zeroes. Also, it makes sense to restrict
the range to positive since this is the length of a velocity vector.
kpreid added a commit that referenced this issue Nov 24, 2024
Part of <#537>.
This doesn’t directly remove any negative-zero hazards, but it is a
more appropriately bounded data type regardless (frame time cannot be
negative).
@kpreid
Copy link
Owner Author

kpreid commented Nov 25, 2024

Whoops, the design of PositiveSign is not consistent. In FP arithmetic, 0.0 * INFINITY is NaN, so as long as PositiveSign includes INFINITY, it isn’t closed under multiplication.

My first thought is to define multiplication such that 0.0 * INFINITY == 0.0, because in the actual applications for PositiveSign, positive infinity should almost always appear only as essentially “would be finite but it is too large to be represented” — we don’t generally get an infinity correctly from a division by zero. That would make PositiveSign no longer merely a restriction, but it might be the least bad thing to do. Redefining arithmetic should be done with care, though.

@kpreid
Copy link
Owner Author

kpreid commented Nov 25, 2024

Implemented 0.0 * INFINITY == 0.0 in b24f917.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: data Things related to the data structures underlying the world, and the functions that manipulate them. kind: bug Something isn't working as it should
Projects
None yet
Development

No branches or pull requests

1 participant