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

Convert Ratio of integers to f64 #52

Merged
merged 7 commits into from
Apr 4, 2020
Merged

Convert Ratio of integers to f64 #52

merged 7 commits into from
Apr 4, 2020

Conversation

MattX
Copy link
Contributor

@MattX MattX commented Jun 21, 2019

Performs the division with integer arithmetic, and rounds
before performing an exact cast to float. This avoids any
issues with rounding.

General method referenced from https://stackoverflow.com/questions/33623875/converting-an-arbitrary-precision-rational-number-ocaml-zarith-to-an-approxim.

Partially fixes #4 (no support for f32 conversion currently).

@maxbla
Copy link
Contributor

maxbla commented Jun 21, 2019

Try running ci/test_full.sh before pushing. This will test your code very similarly to how Travis CI tests it. We should probably add this instruction to the readme, or a contributing.md.

It seems like your code depends on std. This crate supports nostd. If you can make it work with FloatCore, that would be great, but it seems like that isn't possible with your algorithm. You might be able to use integer_decode, min_value and min_positive_value to make this work with FloatCore.

If you want CI to work, try throwing in some #[cfg(feature = "std")]s. After all, if this implementation is specific to f32 and f64s its going to need std.

@MattX
Copy link
Contributor Author

MattX commented Jun 21, 2019

Ok, I'll make sure that passes.

Given that this code needs BigInts, and num-bigint seems to have a hard dependency on std, does it make sense to try and convert it to FloatCore?

@cuviper
Copy link
Member

cuviper commented Jun 21, 2019

You need #[cfg(feature = "bigint")] at least. If you're using any of f64's methods that aren't in core, then we should explicitly require "std" too, as num-bigint may someday work with only core and alloc. FloatCore is only relevant if you're using generic Float, but I think not.

@MattX
Copy link
Contributor Author

MattX commented Jun 21, 2019

Ok that makes sense, I'll add both feature flags.

I think most of what I use is actually in core, except for exp2. It could potentially be replaced by a hand-rolled solution, but I don't think it's really worth it until we actually get std-free BigInts.

@MattX
Copy link
Contributor Author

MattX commented Jun 23, 2019

@maxbla I agree with your comments above, I've pushed a new revision which handles both 16-bit architectures and arbitrarily wide usizes. Thanks for having taken the time to look at this!

@MattX MattX force-pushed the to_f64 branch 4 times, most recently from 0904132 to 7837c55 Compare June 25, 2019 02:15
@MattX
Copy link
Contributor Author

MattX commented Jun 26, 2019

@cuviper, @hauleth, it looks like you guys have merge rights on this repo, would you have time to give this a look?

@MattX
Copy link
Contributor Author

MattX commented Jul 10, 2019

I've moved a bigint-based unit test to the doctests to show the possibility of using BigInts. Does anyone have time to take another look at the review?

@cuviper
Copy link
Member

cuviper commented Jul 12, 2019

Sorry, yes, I mean to give this a deeper review, but haven't gotten to it yet. It just came up in #54 too -- is there a reason you added a new method instead of implementing ToPrimitive as a whole?

@MattX
Copy link
Contributor Author

MattX commented Jul 17, 2019

No particular reason—it's more work to implement all of ToPrimitive, I guess 😛. This code can easily enough be extended to f32s (a particularly trivial implementation being to cast the f64 down), but if possible I'd rather merge this first.

I do have a small reason for not doing the full ToPrimitive, which is that it's not clear to me what the exact semantics of ToPrimitive are. Should None be returned only when the value overflows? Or when it's not exactly representable? We should probably document this in the trait documentation.

@cuviper
Copy link
Member

cuviper commented Jul 17, 2019

This code can easily enough be extended to f32s (a particularly trivial implementation being to cast the f64 down)

FWIW, the default ToPrimitive::to_f32 already does this. The only required methods are to_i64 and to_u64, and the rest should only be implemented if you can do a better job than the naive default. (e.g. a more precise to_f64 as here, or to_u128 that actually uses more bits)

but if possible I'd rather merge this first.

The design of public API is important though, because we'll be stuck with it. I think ToPrimitive is probably the better approach. Maybe we can do both (as discussed here), but if so I'd want to make sure their use is a close as possible, without weird idiosyncrasies between the two options. The surest way to do that is to implement one in terms of the other.

I do have a small reason for not doing the full ToPrimitive, which is that it's not clear to me what the exact semantics of ToPrimitive are. Should None be returned only when the value overflows? Or when it's not exactly representable? We should probably document this in the trait documentation.

Sure, we can and should enhance docs -- the current semantics of the primitive implementations are that they only return None for overflow, or for completely unrepresentable values like NaN to int. Float to integer returns the same value that an as cast would, truncated toward zero.

@MattX
Copy link
Contributor Author

MattX commented Jul 17, 2019 via email

@MattX MattX force-pushed the to_f64 branch 2 times, most recently from 916e0b5 to 89ef262 Compare September 8, 2019 01:00
@MattX
Copy link
Contributor Author

MattX commented Sep 8, 2019

I've pushed a version with ToPrimitive, please let me know what you think.

@MattX
Copy link
Contributor Author

MattX commented Oct 12, 2019

@cuviper, @hauleth, let me know how the CR looks when you have time. I'm happy to make further changes if needed.

@maxbla
Copy link
Contributor

maxbla commented Mar 13, 2020

If the original author doesn't makes the suggested changes, I'd be happy to drag this PR to the finish line.

@cuviper
Copy link
Member

cuviper commented Mar 13, 2020

@maxbla that's fine with me, just keep the original commit for authorship and then add your own. It needs to be rebased too.

@MattX
Copy link
Contributor Author

MattX commented Mar 18, 2020

Hey sorry, I think I missed the review notification. @maxbla if you have time feel free to take over, otherwise I can take a look this weekend.

@maxbla
Copy link
Contributor

maxbla commented Mar 18, 2020

I would be happy for you to make the suggested changes. I only offered because it looked like you were done.

@MattX
Copy link
Contributor Author

MattX commented Mar 18, 2020

Yeah if you have time to get started before this weekend go for it!

MattX added 2 commits March 22, 2020 14:54
Performs the division with integer arithmetic, and rounds
before performing an exact cast to float. This avoids any
issues with rounding.
These can be provided even when BigInts are
unavailable.
@MattX
Copy link
Contributor Author

MattX commented Mar 22, 2020

I've implemented the suggested changes:

  • If big ints and std are available, use that to convert any Ratio of Clone + Integer + ToPrimitive + ToBigInt types
  • Otherwise, ratios of primitive integer types ≤ 32 bits are now always convertible to f64 by converting the numerator and denominator to f64 directly. Ratios of u64 and i64 are convertible if std is available using the same algorithm as BigInt conversion, and using i128 as the supporting type for shifts.

@MattX MattX changed the title Convert ratio of ToBigInt values to f64 Convert Ratio of integers to f64 Mar 22, 2020
Provides an alternative implementation of ToPrimitive
for 64-bit integer types when BigInt is not available.
@cuviper
Copy link
Member

cuviper commented Apr 4, 2020

Looks great, thanks!

bors r+

@bors
Copy link
Contributor

bors bot commented Apr 4, 2020

Build succeeded

@bors bors bot merged commit 07112ea into rust-num:master Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for rounding rational numbers to the nearest f64 and f32
4 participants