Skip to content

Conversation

@tkfu
Copy link

@tkfu tkfu commented Dec 11, 2025

See #160 for the reasoning. Happy to accept change requests, or change the patch so that it's a build-time option whether to use MPFR or not.

@vojtechtrefny
Copy link
Member

Jenkins, ok to test.

@vojtechtrefny
Copy link
Member

I am in favor of this change in general (less dependencies is always better regardless of the license issue). And if we preserve the same functionality, I don't think we need the build time option.

@tkfu
Copy link
Author

tkfu commented Dec 17, 2025

Investigating the test failures in CI now.


static bool multiply_size_by_unit (mpfr_t size, char *unit_str) {
/* Helper function to convert mpf_t to mpz_t with round-toward-zero (truncate decimal) */
static void mpz_set_f_round_zero(mpz_t rop, const mpf_t op) {

Choose a reason for hiding this comment

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

Doesn't libgmp already provide mpz_set_f which does this exact thing? https://gmplib.org/manual/Assigning-Integers

Relying on the formatting and parsing seems hacky.

Copy link
Author

@tkfu tkfu Dec 17, 2025

Choose a reason for hiding this comment

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

It's because libgmp's mpz_set_f doesn't handle the decimal truncation properly (edit: I guess I should say, it doesn't handle truncation the way we would like it to here. it's intended behaviour for libgmp to truncate the binary representation). As noted in the commit introducing mpfr, mpz_set_f(0.1 * 1000) is 99.

Agree that it's a bit hacky, though.

Choose a reason for hiding this comment

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

Are you sure the string based method is different? Is there a test case that fails with mpz_set_f? It seems to me the issue with the 0.1 * 1000 case is not the truncation but the result of the multiplication itself.

Copy link
Author

Choose a reason for hiding this comment

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

.....you're right. Damn, back to the drawing board. Thank you for the careful review. I just assumed the test cases had coverage for this without verifying, and they definitely don't.

MPFR is GPLv3 licensed, which is inconvenient for embedded projects.
This commit removes the MPFR dependency and replaces it with a GMP-only
solution.

The issue: mpz_set_f() truncates binary representation, causing
e.g. 0.1 * 1000 to become 99 instead of 100. We need round-towards-zero
logic.

To deal with this we add a new helper that converts mpf_t to
decimal string, truncates at decimal point, then parses back to mpz_t.
This provides correct decimal rounding equivalent to MPFR's mpfr_get_z()
with MPFR_RNDZ.

All tests pass with the GMP-only implementation.

Signed-off-by: Jon Oster <jon.i.oster@gmail.com>
@tkfu
Copy link
Author

tkfu commented Dec 17, 2025

Thanks to @PlasmaPower for the review, this isn't mergeable and the approach is wrong. I'm going to go back to the drawing board and look for another solution; I'll make sure to add appropriate test cases to the test suite next time.

@tkfu tkfu closed this Dec 17, 2025
@PlasmaPower
Copy link

Could rationals be used instead of floats for this? They seem like a better fit.

@tkfu
Copy link
Author

tkfu commented Dec 17, 2025

Yes! That's exactly what I'm going for now. I did some fuzzing, and MPFR actually also gives incorrect results (ex: 0.0021209044 TB is 2120904399 bytes). The errors are about 10x less frequent than with libgmp, but I think the only way to get universally accurate results is with rationals. Will come back and reopen this when I've got something working.

@tkfu
Copy link
Author

tkfu commented Dec 18, 2025

Ok, fix is done. As promised, I also added tests that will fail either with the MPFR implementation or the GMP-only implementation. Opening a new PR #163 because it seems I don't have the permissions to reopen this one.

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.

3 participants