Philip Miess wrote:
Don wrote:
Philip Miess wrote:
Walter Bright wrote:
Don wrote:
That's true, but if you're in a floatingpoint module, and you call a non-floatingpoint module, it's your responsibility to make sure that the rounding mode is back to normal. You're saying that you don't care about the status flags. So it's your own fault if you get surprising results.

The primary use for adjusting the rounding mode is for things like implementing interval arithmetic. Thus, it's only ever used for small functions.

Perhaps we can go with something simpler. If you call a pure function, then the modes must be set to their defaults.


Walter,
    I had a simpler idea.
What about a default rounding mode parameter on pure functions that care about the rounding mode.

like this

pure int sqrt(int x, invariant roundingMode round = default)
{
    return x*x;
}

No change to D is necessary to use this.
If you wanted to make it a little easier you could
provide a standard rounding mode class that gets the current rounding mode. now if don't want to use the default rounding mode you pass the rounding Mode your using as a parameter.
The function can be cached since it's output only depends on its input.

In summary, if your pure function depends on the rounding mode that should be a parameter of your function.
What do you think, will that work?

Phil


That's actually a LOT more complicated than my suggestion. Also, it's not how the rounding modes work.

Aargh. It seems that people don't understand that my solution DOES fix the problem, and is trivial to implement (< 10 lines of code in the DMD source, one line change in a couple of standard library modules and THAT'S ALL). Nobody has come up with any problems with it.

Especially, I don't think Walter understands my proposal yet.

But thanks for replying to the thread, I think it's an important one to get fixed.


Don,
    here is an improved version of my suggestion

import std.c.fenv;
import std.math;

pure long myround(real x, int round = fegetround() )
{
return lrint(x);
}

int main(char[][] args)
{
    long result;
    result = myround(2.6);
    //result is now 3

    fsetround(FE_DOWNWARD);
    result = myround(2.6);
    //result is now 2
}

I think that this is easier to understand because everything is explicit and uses the normal syntax.
Only functions that really use the mode need to be parametrized.
It requires no change to the compiler, so its simpler for Walter.

Unfortunately, it _does_ require compiler changes. Here are some issues:
(1) The optimiser needs to discard all those calls to fegetround().
(2) It must not display a warning "parameter 'round' is never used".
(3) Every standard math function gets this extra parameter. So taking the address of a standard math function will stop working. (4) The intrinsic functions like sqrt() have signatures which need to change.
(5) Properties stop working.
(6) This doesn't deal with the problem of the exception sticky flags.
(7) It doesn't deal with the problem of floating point exception handling.

It does require a little more typing for the function writer but not much.
No change is necessary for the use of the function since it automatically picks up the current rounding mode. Additionally it does not affect functions that don't need it like your module setting would. That way you don't need to segregate all the functions that use the rounding mode into a separate module to avoid penalizing the others.

But if you look at the functions which need it, you'll find they're nearly all in the same module anyway (locality of reference). Bear in mind that there are very few cases where it is ever used. Originally I had thought of marking every function specifically, but I don't think that complexity is actually necessary.


To be clear, I do understand your suggestion and believe it would work.
I just prefer not to add new elements to the language when there is a
reasonably good solution already available.

I can only think of one such possible solution[1]. My first proposal was the next best thing: the most trivial possible language change, and actually giving the compiler additional freedom in exchange.

[1] My second proposal was to provide a runtime call to disable caching of pure functions, but that requires every pure function to check a global variable to see if caching of pure functions should be ignored. Unfortunately, this loses many of the optimisation benefits of 'pure', and the extra optimisation benefits from my first proposal. So I prefer my first proposal. But if you insist on no language changes at all, this is the simplest way to do it.

Reply via email to