Skip to content

Fix float number overflow in range rand method #13825

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

erdian718
Copy link
Contributor

Closes: #7883

Copy link
Contributor

@HertzDevil HertzDevil left a comment

Choose a reason for hiding this comment

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

Float64::MIN..Float32::MAX still overflows, in case you want to fix that as well

@erdian718
Copy link
Contributor Author

Float64::MIN..Float32::MAX still overflows, in case you want to fix that as well

Instead of returning Infinity, rand(Float64::MIN..Float32::MAX) will raise a exception, this is intentional. The caller should be aware that Float64::MIN is -Infinity for Float32. I'm not going to deal with random numbers about Infinity.
The following will also raise exception (not return Infinity):

rand(0.0..Float64::INFINITY)
rand(Float64::NAN..Float64::NAN)

We could indeed handle overflow issues with inconsistent start and end types of ranges with more code, but I don't think it's worth it, and throwing an exception tells the caller to remind the caller to improve the code is simpler and clearer.

The optimizations I made are just the usual practice in the field of numerical calculations.

@HertzDevil
Copy link
Contributor

Instead of returning Infinity, rand(Float64::MIN..Float32::MAX) will raise a exception, this is intentional. The caller should be aware that Float64::MIN is -Infinity for Float32

rand returns a value with the same type as the range's begin value, consistent with other methods on Range. The actual value of Float32::MAX - Float64::MIN definitely fits into Float64's finite range. If anything, by this logic it is Float32::MIN..Float64::MAX that should intentionally overflow, not the opposite.

Replacing expressions like end - begin with -begin + end should do the job.

@erdian718
Copy link
Contributor Author

erdian718 commented Sep 22, 2023

If want to consider the return value type, expect inconsistencies if big numbers are involved:

rand(BigFloat.new(0)..1.0)
rand(0.0..BigFloat.new(1))

I was wondering if it should be like rand(range: range(Int, Int)) to restrict the begin and end elements of the range to the same type.

@erdian718
Copy link
Contributor Author

I found that the current implementation does not support big numbers.
I think the improved implementation should only support Float64 and Float32, and the begin and end types of the Range should be the same, consistent with the case of Int.

@Blacksmoke16 Blacksmoke16 added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib labels Sep 22, 2023
Copy link
Member

@straight-shoota straight-shoota left a comment

Choose a reason for hiding this comment

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

I figure that changing the algorithm for rand(Range) should take #12546 into account. Are you aware of that issue?
This implementation seems to exhibit the same correctness problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using the full Float64 range in Random returns Infinity every time
4 participants