Skip to content

std.format: Prepare to add %g (step 1).#7810

Merged
dlang-bot merged 1 commit intodlang:masterfrom
berni44:format_add_g
Mar 1, 2021
Merged

std.format: Prepare to add %g (step 1).#7810
dlang-bot merged 1 commit intodlang:masterfrom
berni44:format_add_g

Conversation

@berni44
Copy link
Contributor

@berni44 berni44 commented Feb 24, 2021

This step is the decision, if a %e-like or a %f-like output should be created. According to the specs %g produces the shorter of the two. That's wrong. The cutting points depend on the requested precision, roughly between 10^^precision and 0.0001 %f is used and %e else (sign ignored here). Different rounding modes make this a little bit more difficult, but doable. The result looks like this:

    final switch (rm)
    {
    case RoundingMode.up:
        useE = abs(val) >= 10.0 ^^ f.precision - (val > 0 ? 1 : 0)
            || abs(val) < 0.0001 - (val > 0 ? (10.0 ^^ (-4 - f.precision)) : 0);
        break;
    case RoundingMode.down:
        useE = abs(val) >= 10.0 ^^ f.precision - (val < 0 ? 1 : 0)
            || abs(val) < 0.0001 - (val < 0 ? (10.0 ^^ (-4 - f.precision)) : 0);
        break;
    case RoundingMode.toZero:
        useE = abs(val) >= 10.0 ^^ f.precision
            || abs(val) < 0.0001;
        break;
    case RoundingMode.toNearestTiesToEven:
    case RoundingMode.toNearestTiesAwayFromZero:
        useE = abs(val) >= 10.0 ^^ f.precision - 0.5
            || abs(val) < 0.0001 - 0.5 * (10.0 ^^ (-4 - f.precision));
        break;
    }

Unfortunately, for some corner cases, this does not result in an identical choice, compared with snprintf, which means, in really rare circumstances, this could break code. (I still advocate for using this, see below.)

To get around this, I added own functions for 10.0 ^^ +n and 10.0 ^^ -n, which use integer arithmetics instead of floating point arithmetics.

A second problem arises now: D may use internally reals to do the calculation, but the size of real may vary, depending on the computer used. All in all, we still cannot rely on anything and have to continue to simulate floating point math, using integers. I did this with the functions less which are easy to implement. To be really sure, we would also need a simulation of - and *, which is much more complicated. Further, I'm not sure, if this all works with real==double-reals.

All in all, I would prefer to just use the code I gave above and to accept, that there are rare corner cases, where the proposed implementation differs from the one of snprintf. (It would mean, that we have to loosen the added unittests a little bit, by adding some more nextUp/nextDown, leaving a gap of uncertainity.)

What do you think?

@dlang-bot
Copy link
Contributor

Thanks for your pull request and interest in making D better, @berni44! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + phobos#7810"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants